51Nod 最大公因数之和+最小公倍数之和(杜教筛)

1238 最小公倍数之和

http://www.51nod.com/Challenge/Problem.html#!#problemId=1238

1237 最大公因数之和

http://www.51nod.com/Challenge/Problem.html#!#problemId=1237

先来说最大公因数之和:

1237 最大公因数之和

∑ i = 1 n ∑ j = 1 n gcd ⁡ ( i , j ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd(i,j) i=1nj=1ngcd(i,j)
= ∑ i = 1 n ∑ j = 1 n d [ gcd ⁡ ( i , j ) = d ] =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}d[\gcd(i,j)=d] =i=1nj=1nd[gcd(i,j)=d]
= ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ [ gcd ⁡ ( i , j ) = 1 ] =\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}[\gcd(i,j)=1] =d=1ndi=1dnj=1dn[gcd(i,j)=1]
而 gcd ⁡ ( i , j ) = 1 等 同 于 ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) 而\gcd(i,j)=1等同于\sum\limits_{k|\gcd(i,j)}\mu(k) gcd(i,j)=1kgcd(i,j)μ(k)
所 以 原 式 = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) 所以原式=\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{k|\gcd(i,j)}\mu(k) =d=1ndi=1dnj=1dnkgcd(i,j)μ(k)
把 k 提 到 前 面 把k提到前面 k
原 式 = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ n k d ⌋ 1 设 函 数 S ( n ) = ∑ i = 1 n ∑ j = 1 n 1 原 式 = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) S ( n k d ) 令 T = k d , 原 式 = ∑ T = 1 n S ( n T ) ∑ k ∣ T μ ( k ) T k 因 为 μ ∗ i d = φ ( ∗ 为 狄 利 克 雷 卷 积 ) 所 以 原 式 = ∑ T = 1 n S ( n T ) φ ( T ) 原式=\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)\sum\limits_{i=1}^{\lfloor{\frac{n}{kd}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{kd}}\rfloor}1\\ 设函数S(n) = \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}1\\ 原式=\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)S(\frac{n}{kd})\\ 令T=kd, 原式=\sum\limits_{T=1}^{n}S(\frac{n}{T})\sum\limits_{k|T}\mu(k)\frac{T}{k}\\ 因为\mu*id=\varphi (*为狄利克雷卷积)\\ 所以 原式=\sum\limits_{T=1}^{n}S(\frac{n}{T})\varphi(T) =d=1ndk=1dnμ(k)i=1kdnj=1kdn1S(n)=i=1nj=1n1=d=1ndk=1dnμ(k)S(kdn)T=kd,=T=1nS(Tn)kTμ(k)kTμid=φ()=T=1nS(Tn)φ(T)
那么结果就显而易见了,结果就是欧拉函数的和,但是我们发现这个n是1e10的大小,线性筛会超时,所以欧拉函数的前缀和我们需要用杜教筛来求得,
我们知道 ϕ ∗ I = i d \phi*I=id ϕI=id,所以我们可以直接套杜教筛的公式
S ( n ) = ∑ i = 1 n φ ( i ) g ( 1 ) S ( n ) = ∑ i = 1 n ( g ∗ S ) ( n ) − ∑ i = 2 n g ( i ) S ( ⌊ n i ⌋ ) S(n)=\sum\limits_{i=1}^{n}\varphi(i) \\g(1)S(n)=\sum\limits_{i=1}^{n}(g*S)(n)-\sum\limits_{i=2}^{n}g(i)S(\lfloor{\frac{n}{i}}\rfloor) S(n)=i=1nφ(i)g(1)S(n)=i=1n(gS)(n)i=2ng(i)S(in)
g函数为 I I I
那么原式= ∑ i = 1 n i − ∑ i = 2 n S ( ⌊ n i ⌋ ) = n ( n + 1 ) 2 − ∑ i = 2 n S ( ⌊ n i ⌋ ) \sum\limits_{i=1}^{n}i-\sum\limits_{i=2}^{n}S(\lfloor{\frac{n}{i}}\rfloor)\\ =\frac{n(n+1)}{2}-\sum\limits_{i=2}^{n}S(\lfloor{\frac{n}{i}}\rfloor) i=1nii=2nS(in)=2n(n+1)i=2nS(in)
对于杜教筛我们可以预先处理 n 2 3 n^{\frac{2}{3}} n32的结果,然后后面的用杜教筛公式递归求得

AC代码:

#include 

using namespace std;
#define LL long long
const int M = 5e6;
const int Mod = 1e9 +7;
const double eps = 0.000000001;
LL phi[M + 30], prim[M + 30], tot;
bool mark[M + 30];
map<LL, LL> m;
#define inv_2 (Mod+1)/2

LL Add(LL a, LL b) {
    LL c = (a + b) % Mod;
    if(c >= Mod) return c - Mod;
    if(c < 0) return c + Mod;
    return c;
}

void init() {
    phi[1] = 1;
    for(LL i = 2; i <= M; i ++) {
        if(!mark[i]) {
            prim[++tot] = i;
            phi[i] = i - 1;
        }
        for (LL j = 1; j <= tot; j ++) {
            if(i * prim[j] > M) break;
            mark[i * prim[j]] = 1;
            if(i % prim[j] == 0) {
                phi[i * prim[j]] = phi[i] * prim[j];
                break;
            }
            phi[i *prim[j]] = phi[i] * phi[prim[j]];
        }
    }
    for (int i = 1; i <= M; i ++) phi[i] = Add(phi[i-1], phi[i]);
}

LL getPhi(LL n) {
    if(n <= M) return phi[n];
    if(m[n]) return m[n];
    LL ans;
    ans = 1LL * n % Mod * (n % Mod + 1) % Mod * inv_2 % Mod;
    for (LL l = 2, r; l <= n; l = r + 1) {
        r = n/(n/l);
        ans = (ans - (r - l + 1) % Mod * getPhi(n/l) % Mod + Mod) % Mod;
    }
    return m[n] = ans;
}
LL solve(LL n) {
    LL ans = 0;
    for (LL l = 1, r; l <= n; l = r + 1) {
        r = n/(n/l);
        ans = Add(ans, 1ULL * (n/l) % Mod * (n/l) % Mod * (Add(getPhi(r) % Mod, -getPhi(l-1) % Mod)  ) % Mod);
    }
    return ans;
}

int main()
{
    init();
    LL n;
    cin >> n;
    m.clear();
    cout << solve(n) << endl;
    return 0;
}

1238 最小公倍数之和

∑ i = 1 n ∑ j = 1 n l c m ( i , j ) = ∑ i = 1 n ∑ j = 1 n i j d [ gcd ⁡ ( i , j ) = d ] = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ i j [ gcd ⁡ ( i , j ) = 1 ] = ∑ d = 1 n d ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ n d ⌋ ∑ k ∣ gcd ⁡ ( i , j ) μ ( k ) i j = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) k 2 ∑ i = 1 ⌊ n k d ⌋ ∑ j = 1 ⌊ n k d ⌋ i j \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}lcm(i,j)\\ =\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\frac{ij}{d}[\gcd(i,j)=d]\\ =\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}ij[\gcd(i,j)=1]\\ =\sum\limits_{d=1}^{n}d\sum\limits_{i=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{d}}\rfloor}\sum\limits_{k|\gcd(i,j)}\mu(k)ij\\ =\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)k^2\sum\limits_{i=1}^{\lfloor{\frac{n}{kd}}\rfloor}\sum\limits_{j=1}^{\lfloor{\frac{n}{kd}}\rfloor}ij i=1nj=1nlcm(i,j)=i=1nj=1ndij[gcd(i,j)=d]=d=1ndi=1dnj=1dnij[gcd(i,j)=1]=d=1ndi=1dnj=1dnkgcd(i,j)μ(k)ij=d=1ndk=1dnμ(k)k2i=1kdnj=1kdnij
令 S ( n ) = ∑ i = 1 n ∑ j = 1 n i j 原 式 = ∑ d = 1 n d ∑ k = 1 ⌊ n d ⌋ μ ( k ) k 2 S ( ⌊ n k d ⌋ ) 令 T = k d 原 式 = ∑ T = 1 n S ( ⌊ n T ⌋ ) ∑ k ∣ T μ ( k ) k 2 ( T k ) = ∑ T = 1 n S ( ⌊ n T ⌋ ) T ∑ k ∣ T μ ( k ) k 令 f ( n ) = n ∑ k ∣ n μ ( k ) k 原 式 化 简 为 = ∑ T = 1 n S ( ⌊ n T ⌋ ) f ( T ) 令 f ∗ i d 2 ( ∗ 为 狄 利 克 雷 卷 积 ) f ∗ i d 2 = ∑ d ∣ n f ( d ) ⋅ ( n d ) 2 = ∑ d ∣ n d ⋅ ∑ k ∣ d μ ( k ) ⋅ k ⋅ ( n d ) 2 = ∑ d ∣ n n ∑ k ∣ d μ ( k ) ⋅ k ⋅ ( n d ) 令 t ( n ) = ∑ k ∣ d μ ( d ) ⋅ d t ( n ) = [ ( μ ⋅ i d ) ∗ 1 ] 则 f ∗ i d 2 = n ∑ d ∣ n ⋅ t ( d ) ⋅ ( n d ) = n [ ( μ ⋅ i d ) ∗ 1 ∗ i d ] = n [ ( μ ⋅ i d ) ∗ i d ∗ 1 ] = n [ ( ∑ d ∣ n ( μ ( d ) ⋅ d ) ⋅ ( n d ) ) ∗ 1 ] = n [ ( n ∑ d ∣ n μ ( d ) ) ∗ 1 ] = n [ e ∗ 1 ] = n 带 入 杜 教 筛 的 公 式 g ( 1 ) S ( n ) = ∑ i = 1 n ( g ∗ S ) ( n ) − ∑ i = 1 n g ( i ) S ( ⌊ n i ⌋ ) g ( n ) = i d 2 , S ( n ) = n ∑ k ∣ n μ ( k ) k 所 以 g ( 1 ) S ( n ) = ∑ i = 1 n i − ∑ i = 1 n i 2 S ( ⌊ n i ⌋ ) = n ⋅ ( n + 1 ) 2 − ∑ i = 1 n i 2 S ( ⌊ n i ⌋ ) 令S(n)=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}ij\\ 原式=\sum\limits_{d=1}^{n}d\sum\limits_{k=1}^{\lfloor{\frac{n}{d}}\rfloor}\mu(k)k^2S(\lfloor{\frac{n}{kd}}\rfloor)\\ 令T=kd\\ 原式=\sum\limits_{T=1}^{n}S(\lfloor{\frac{n}{T}}\rfloor)\sum\limits_{k|T}\mu(k)k^2(\frac{T}{k})\\ =\sum\limits_{T=1}^{n}S(\lfloor{\frac{n}{T}}\rfloor)T\sum\limits_{k|T}\mu(k)k \\令f(n)=n\sum\limits_{k|n}\mu(k)k\\ 原式化简为=\sum\limits_{T=1}^{n}S(\lfloor{\frac{n}{T}}\rfloor)f(T)\\ 令f*id^2(*为狄利克雷卷积)\\ f*id^2=\sum\limits_{d|n}f(d)\cdot(\frac{n}{d})^2\\ =\sum\limits_{d|n}d\cdot\sum\limits_{k|d}\mu(k)\cdot k\cdot(\frac{n}{d})^2\\ =\sum\limits_{d|n}n\sum\limits_{k|d}\mu(k)\cdot k\cdot(\frac{n}{d})\\ 令t(n) = \sum\limits_{k|d}\mu(d) \cdot d\\ t(n)=[(\mu\cdot id)*1]\\ 则f*id^2=n\sum\limits_{d|n}\cdot t(d)\cdot (\frac{n}{d})\\ =n[(\mu\cdot id)*1*id]\\ =n[(\mu\cdot id)*id*1]\\ =n[(\sum\limits_{d|n}(\mu(d) \cdot d)\cdot(\frac{n}{d}))*1]\\ =n[(n\sum\limits_{d|n}\mu(d))*1]\\ =n[e*1]\\ =n\\ 带入杜教筛的公式\\ g(1)S(n)=\sum\limits_{i=1}^{n}(g*S)(n)-\sum\limits_{i=1}^{n}g(i)S(\lfloor{\frac{n}{i}}\rfloor)\\ g(n)=id^2, S(n)=n\sum\limits_{k|n}\mu(k)k\\ 所以g(1)S(n)=\sum\limits_{i=1}^{n}i-\sum\limits_{i=1}^{n}i^2S(\lfloor{\frac{n}{i}}\rfloor)\\ =\frac{n\cdot(n+1)}{2}-\sum\limits_{i=1}^{n}i^2S(\lfloor{\frac{n}{i}}\rfloor) S(n)=i=1nj=1nij=d=1ndk=1dnμ(k)k2S(kdn)T=kd=T=1nS(Tn)kTμ(k)k2(kT)=T=1nS(Tn)TkTμ(k)kf(n)=nknμ(k)k=T=1nS(Tn)f(T)fid2()fid2=dnf(d)(dn)2=dndkdμ(k)k(dn)2=dnnkdμ(k)k(dn)t(n)=kdμ(d)dt(n)=[(μid)1]fid2=ndnt(d)(dn)=n[(μid)1id]=n[(μid)id1]=n[(dn(μ(d)d)(dn))1]=n[(ndnμ(d))1]=n[e1]=ng(1)S(n)=i=1n(gS)(n)i=1ng(i)S(in)g(n)=id2,S(n)=nknμ(k)kg(1)S(n)=i=1nii=1ni2S(in)=2n(n+1)i=1ni2S(in)
这样f的前做个就可以算出,而结果 ∑ T = 1 n S ( ⌊ n T ⌋ ) f ( T ) \sum\limits_{T=1}^{n}S(\lfloor{\frac{n}{T}}\rfloor)f(T) T=1nS(Tn)f(T)
分块处理一下即可

AC代码:

#include 

using namespace std;
#define LL long long
const int M = 5e6 + 5;
const int Mod = 1e9 + 7;
const double eps = 0.000000001;
const int inf = 0x3f3f3f3f;
#define inv_2 (Mod+1)/2
#define inv_6 (Mod+1)/6

LL mu[M + 30], prim[M + 30];
bool vis[M + 30];
LL F[M + 30];
map<LL, LL> m;


void Add(LL &a, LL b) {
    a += b;
    if(a >= Mod) a -= Mod;
    if(a <= - Mod) a += Mod;
}


void Mobius(){
    mu[1] = 1;
    int tot = 0;
    for (int i = 2; i <= M; i ++) {
        if(!vis[i]) {
            prim[tot ++] = i;
            mu[i] = -1;
        }
        for (int j = 0; j < tot; j ++) {
            if(i * prim[j] > M) break;
            vis[i * prim[j]] = true;
            if(i % prim[j] == 0) {
                mu[i * prim[j]] = 0;
                break;
            }
            mu[i * prim[j]] = -mu[i];
        }
    }
    for (int i = 1; i <= M; i ++)
        for (int j = 1; j * i <= M; j ++)
            Add(F[i*j], mu[i] * i % Mod);
    for (int i = 1; i <= M; i ++) F[i] = F[i] * i % Mod;
    for (int i = 1; i <= M; i ++) Add(F[i], F[i-1]);
}

LL getX(LL X) {
    X %= Mod;
    return 1ULL * X * (X + 1) % Mod * (2 * X + 1) % Mod * inv_6 % Mod;
}

LL getX_2(LL l, LL r) {
    return 1ULL * (r - l + 1) % Mod * ((r + 1) % Mod) % Mod * inv_2 % Mod;
}

LL getS(LL n) {
    if(n <= M) return F[n];
    if(m[n]) return m[n];
    LL ans = 1ULL * n % Mod * (n+1) % Mod * inv_2 % Mod;
    for (LL l = 2, r; l <= n; l = r + 1) {
        r = n/(n/l);
        Add(ans, -((getX(r) - getX(l-1)) % Mod * getS(n/l) % Mod));
    }
    return m[n] = ans;
}

LL solve(LL n) {
    LL ans = 0;
    for (LL l = 1, r; l <= n; l = r + 1) {
        r = n/(n/l);
        LL k = getX_2(1, n/l);
        Add(ans, (k % Mod * k % Mod * ((getS(r) - getS(l-1)) % Mod) % Mod));
    }
    return (ans + Mod) % Mod;
}

int main()
{
    Mobius();
    LL n;
    scanf("%lld", &n);
    printf("%lld\n", solve(n));
    return 0;
}

你可能感兴趣的:(题解,杜教筛,数论)