• 51Nod1220:约数之和


    51Nod1220:约数之和

    题意:

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

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

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

    给出(Nleq 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}^Nsum_{j=1}^Nsum_{x|i}sum_{y|j}[gcd(x,y)=1]frac{yi}{x} ]

    反演:

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

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

    [sum_{d=1}^Nmu(d)sum_{i=1}^Nsum_{j=1}^Nsum_{xd|i}sum_{yd|j}frac{yi}{x}\sum_{d=1}^Ndmu(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}^Ndmu(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}^Ndmu(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}=nsum_{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}^nsigma(i) ]

    怎么计算呢?

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

    [sum_{i=1}^nsigma(i)=sum_{i=1}^nifrac{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;
    }
    
    
  • 相关阅读:
    安装wampserver时提示丢失MSVCR110.dll(在windows server上可用)
    前端开发必备!Emmet使用手册
    Markdown 新手指南
    封装系统(以封装Windows 7为例)
    简体中国版文档的Markdown语法
    sublime text 3 快捷键大全以及配置编译环境
    windows下的命令行工具babun
    Android屏幕适配全攻略(最权威的官方适配指导)
    JMETER第五节课jenkis集成常态化压测的实战?主从压力机实战??
    性能测试5--Jmeter命令行与以及普罗米修斯的原理
  • 原文地址:https://www.cnblogs.com/zxytxdy/p/12639922.html
Copyright © 2020-2023  润新知