hdu 6706

杜教筛+欧拉函数

答案等价于

$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}$

$=nsum_{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
", 1LL * (dj(n) - 1) * inv2 % P);
    }
    return 0;
} 
View Code
原文地址:https://www.cnblogs.com/19992147orz/p/11403454.html