标签:void printf src span amp onclick ini name ons
杜教筛+欧拉函数
答案等价于
$\sum_{i=1}^{n}\sum_{j=1}^{i}{(i-j)[gcd(i,j)==1]}$
欧拉函数$\phi(i)$表示比$i$小且与$i$互质的数的个数
那么进一步化简,答案等于
$\frac{\sum_{i=1}^{n}{\phi(i)*i}}{2}-1$
$\phi{i}*i$是一个积性函数,可以杜教筛
设$f(i)=\phi(i)*i$,$g(i)=i$
那么
$f*g=\sum_{n|d}{f(d)*\frac{n}{d}}$
$=\sum_{n|d}{\phi(d)*d*\frac{n}{d}}$
$=\sum_{n|d}{\phi(d)*n}$
$=n\sum_{n|d}{\phi(d)}$
因为$\sum_{n|d}{\phi(d)}=n$
所以$f*g=n^{2}$
那么就可以杜教筛了
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 5, P = 1e9 + 7, inv2 = 500000004, inv6 = 166666668; int n, a, b; int phi[maxn], p[maxn], mark[maxn]; map<int, int> mp; void init() { phi[1] = 1; for(int i = 2; i < maxn; ++i) { if(!mark[i]) { p[++p[0]] = i; phi[i] = i - 1; } for(int j = 1; j <= p[0] && i * p[j] < maxn; ++j) { mark[i * p[j]] = 1; if(i % p[j] == 0) { phi[i * p[j]] = phi[i] * p[j]; break; } phi[i * p[j]] = phi[i] * phi[p[j]]; } } for(int i = 1; i < maxn; ++i) { phi[i] = (1LL * phi[i] * i % P + phi[i - 1]) % P; } } int cal(int x) { return 1LL * x * (x + 1) % P * inv2 % P; } int dj(int n) { if(n < maxn) return phi[n]; if(mp.find(n) != mp.end()) return mp[n]; int ret = 1LL * n * (n + 1) % P * (2LL * n + 1) % P * inv6 % P; for(int i = 2, j; i <= n; i = j + 1) { j = n / (n / i); ret = (ret - 1LL * (cal(j) - cal(i - 1) + P) % P * dj(n / i) % P + P) % P; } return mp[n] = ret; } int main() { init(); int T; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &a, &b); printf("%d\n", 1LL * (dj(n) - 1) * inv2 % P); } return 0; }
标签:void printf src span amp onclick ini name ons
原文地址:https://www.cnblogs.com/19992147orz/p/11403454.html