51Nod1220:约数之和

51Nod1220:约数之和

题意:

\(d(k)\)表示\(k\)所有约数的和。

比如说\(d(6)=1+2+3+6=12\)

定义:\(S(N)=\sum_{i=1}^N\sum_{j=1}^Nd(i*j)\)

给出\(N\leq 10^9\),求\(S(N)\)

思路:

我们知道:\(\sigma(n)\)表示约数个数和,且为积性函数。

我们需要求\(\sigma(ij)\),但是\(\sigma\)不是完全积性函数。

这里有个结论:

\[\sigma(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\frac{yi}{x} \]

代入原式:

\[\sum_{i=1}^N\sum_{j=1}^N\sum_{x|i}\sum_{y|j}[gcd(x,y)=1]\frac{yi}{x} \]

反演:

\[\sum_{i=1}^N\sum_{j=1}^N\sum_{x|i}\sum_{y|j}\frac{yi}{x}\sum_{d|gcd(x,y)}\mu(d)\\\sum_{i=1}^N\sum_{j=1}^N\sum_{x|i}\sum_{y|j}\frac{yi}{x}\sum_{d|x,d|y}\mu(d) \]

改变枚举项为\(xd,yd\),接着修改为\(id,jd\)

\[\sum_{d=1}^N\mu(d)\sum_{i=1}^N\sum_{j=1}^N\sum_{xd|i}\sum_{yd|j}\frac{yi}{x}\\\sum_{d=1}^Nd\mu(d)\sum_{i=1}^\frac{N}{d}\sum_{j=1}^\frac{N}{d}\sum_{x|i}\sum_{y|i}\frac{yi}{x} \]

分配一下:

\[\sum_{d=1}^Nd\mu(d)(\sum_{i=1}^\frac{N}{d}\sum_{x|i}\frac{i}{x})(\sum_{j=1}^\frac{N}{d}\sum_{y|i}y) \]

那这后面不就是约数的平方嘛。

\[\sum_{d=1}^Nd\mu(d)\sum_{i=1}^\frac{N}{d}\sigma^2(i) \]

显然后面可以数论分块一下,前面可以杜教筛一下。

先看看怎么样怎样杜教筛这个式子:

\(f=\mu id,g=id\),那么有:

\[(f*g)(n)=\sum_{d|n}(\mu(d)d)\frac{n}{d}=n\sum_{d|n}\mu(d)=[n=1] \]

又有:

\[g(1)S(n)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\frac{n}{i}) \]

可以得到:

\[S(n)=1-\sum_{i=2}^niS(\frac{n}{i}) \]

之后要求这个:

\[\sum_{i=1}^n\sigma(i) \]

怎么计算呢?

需要有点逆向思维,枚举约数不好弄就枚举倍数,所以有:

\[\sum_{i=1}^n\sigma(i)=\sum_{i=1}^ni\frac{n}{i} \]

此时理清楚就可以写代码了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 3e6;
const int inv2 = 500000004;
bool vis[maxn+10];
ll mu[maxn+10];
int primes[maxn+10], cnt;

void init(int n)
{
    mu[1] = 1;
    for(int i = 2; i <= n; i++)
    {
        if(!vis[i])
        {
            primes[++cnt] = i;
            mu[i] = -1;
        }
        for(int j = 1; primes[j] <= n/i; j++)
        {
            vis[primes[j]*i] = 1;
            if(i % primes[j] == 0) break;
            else mu[i*primes[j]] = -mu[i];
        }
    }
    for(int i = 1; i <= n; i++)
    {
        mu[i] = i*mu[i]%mod;
        mu[i] = (mu[i]+mu[i-1])%mod;
    }
}

unordered_map<ll, ll> Smu;

ll getSmu(ll n)
{
    if(n <= maxn) return mu[n];
    if(Smu[n]) return Smu[n];
    ll res = 1;
    for(ll l = 2, r; l <= n; l = r+1)
    {
        r = n/(n/l);
        res -= (r-l+1)%mod*(r+l)%mod*inv2%mod*getSmu(n/l)%mod;
        res = ((res%mod)+mod)%mod;
    }
    return Smu[n] = res;
}

ll n;
unordered_map<ll, ll> G;
ll getG(ll n)
{
    if(G[n]) return G[n];
    ll res = 0;
    for(ll l = 1, r; l <= n; l = r+1)
    {
        r = n/(n/l);
        res = (res + (r-l+1)%mod*(r+l)%mod*inv2%mod*(n/l)%mod)%mod;
    }
    return G[n] = res;
}

int main()
{
    init(maxn);
    cin >> n;

    ll res = 0;
    for(ll l = 1, r; l <= n; l = r+1)
    {
        r = n/(n/l);
        res = (res + ((getSmu(r)-getSmu(l-1))%mod+mod)%mod*getG(n/l)%mod*getG(n/l)%mod)%mod;
    }
    res = ((res%mod)+mod)%mod;
    cout << res << endl;
    return 0;
}

posted @ 2020-04-05 23:26  zhaoxiaoyun  阅读(229)  评论(0编辑  收藏  举报