51NOD 1237 最大公约数之和 V3(杜教筛)

题意

求 $\sum_{i=1}^n \sum_{j=1}^n gcd(i,j)$.

分析

$$\begin{aligned}
\sum_{i=1}^n \sum_{j=1}^n gcd(i,j)  &= \sum_{i=1}^n \sum_{j=1}^n d[gcd(i, j)=d] \\
&= \sum_{d=1}^n d \sum_{i=1}^n \sum_{j=1}^n[gcd(i,j=d)] \\
&= \sum_{d=1}^n d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}\mu (i) \left \lfloor \frac{n}{id} \right \rfloor\left \lfloor \frac{n}{id} \right \rfloor \\
&= \sum_{T=1}^n ({\frac{n}{T}})^2 \sum_{d|T}d\mu (\frac{T}{d}) \\
&= \sum_{T=1}^n ({\frac{n}{T}})^2 \varphi (T)
\end{aligned}$$

使用了几个套路,

一是 $gcd(i,j)=d$ 的经典求和式子;

二是出现 $\sum_{d=1}^n d \sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}$,枚举 $T=id$;

三是使用结论 $\mu * ID = \varphi$.

求欧拉函数的前缀和可以使用杜教筛。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 2000010;
typedef long long ll;
const ll mod = 1000000007;
const ll inv2 = (mod+1)>>1;
ll T, n, pri[maxn], tot, phi[maxn], sum_phi[maxn];
bool vis[maxn];
unordered_map<ll, ll> mp_phi;  //可换成unordered_map
ll S_phi(ll x) {
  if (x < maxn) return sum_phi[x];
  if (mp_phi[x]) return mp_phi[x];
  ll ret = (x%mod) * ((x+1)%mod) % mod * inv2 % mod;
  for (ll i = 2, j; i <= x; i = j + 1) {
    j = x / (x / i);
    ret =(ret - S_phi(x / i) * (j - i + 1) % mod + mod) % mod;
  }
  return mp_phi[x] = ret;
}
void initPhi()
{
  phi[1] = 1;
  for (int i = 2; i < maxn; i++) {
    if (!vis[i]) pri[++tot] = i, phi[i] = i-1;
    for (int j = 1; j <= tot && i * pri[j] < maxn; j++) {
      vis[i * pri[j]] = true;
      if (i % pri[j] == 0)
      {
          phi[i * pri[j]] = phi[i] * pri[j] % mod;
          break;
      }
      else
      {
          phi[i * pri[j]] = phi[i] * phi[pri[j]] % mod;
      }
    }
  }
  for (int i = 1; i < maxn; i++) sum_phi[i] = (sum_phi[i - 1] + phi[i]) % mod;
}

void solve()
{
    ll res = 0;
    for(ll i = 1, j;i <= n;i = j+1)
    {
        j = n / (n / i);
        ll tmp = (n/i) % mod;
        res = (res + tmp * tmp % mod * (S_phi(j)-S_phi(i-1) + mod) % mod) % mod;
    }
    printf("%lld\n", res);
}

int main() {
  initPhi();
  scanf("%lld", &n);
  solve();
  return 0;
}

 

 

参考链接:

1. http://www.ishenping.com/ArtInfo/1581096.html

2. https://oi-wiki.org/math/du/

上一篇:Java基础学习笔记二 Java基础语法


下一篇:如何安装java