51nod(1220 约数之和 推式子反演+线性筛+杜教筛)

题目
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第1张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第2张图片
1.学会线性筛出 d(i):i 约数的个数 以及 dd(i):i 所有约数之和。

学习链接
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第3张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第4张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第5张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第6张图片2.慢慢推式子 需要用到 一个小结论(挺好yy证明的)+反演+积累技巧把(比如dd前缀和可以转化成别的式子进而分块求)
学习链接
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第7张图片第三个式子是反演得到的。最后一个橙点点有一丢丢小错误sigma(q=[1,[n/d]).
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第8张图片我还是自己再次按照上述过程首推一下(由于我的式子太丑啦T_T放在代码后面留着自己看)

#include
#include
#include
using namespace std;
typedef long long ll;
const int N=5e6+5,mod=1e9+7,inv2=500000004;
int is[N+5],prime[N+5];
int dd[N+5],mud[N+5],low[N+5];//dd[i]:i的约数之和 mud[i]=mu[i]*i 
void init()//low[i]=1+p1+p1^2+p1^3+..+p1^e1;(p1为i质因数分解的最小项 e1是分解后p1的指数)
{
     
    mud[1]=1*1,dd[1]=1;int tot=0;
    for(int i=2;i<=N;++i)
    {
     
        if(!is[i]) prime[++tot]=i,mud[i]=-i,dd[i]=low[i]=i+1;
        for(int j=1;j<=tot&&(ll)i*prime[j]<=N;++j)
        {
     
            int t=i*prime[j];is[t]=1;
            if(i%prime[j]==0)
            {
     
                mud[t]=0;//i中含有prime[j],t中prime[j]的指数>=2 所以mu[t]=0,mud[t]=0*t=0;
                low[t]=(ll)low[i]*prime[j]%mod+1,low[t]%=mod;//prime[j]的指数增大1
                dd[t]=(ll)dd[i]/low[i]*low[t]%mod;//除以原来的最小项然后乘以新的最小项
                break;
            }
            mud[t]=(ll)mud[i]*(-prime[j])%mod;//i含有的质因子都大于prime[j] 首先mu[t]=-mu[i] 然后乘了一个prime[j]   也可以直接按积性函数mu[t]=mu[i]*mu[prime[j]];
            low[t]=(prime[j]+1)%mod,dd[t]=(ll)dd[i]*low[t]%mod;//t的最小质因子是prime[j] t的最小项成为prime[j]+1 
        }                                       //dd[t]就是dd[i]多乘以新的质因子prime[j]的贡献 low[t]=pirme[j]+1
    }
    for(int i=1;i<=N;++i) mud[i]=((ll)mud[i]+mud[i-1])%mod,dd[i]=((ll)dd[i]+dd[i-1])%mod;
}
map<int,int>ans_mud;
inline int cal(ll l,ll r){
     //id [l,r]之和
    return (l+r)%mod*((r-l+1)%mod)%mod*inv2%mod;
}
inline int f_mud(ll n){
     //f=mu*d g=id f卷积g=n*e
    if(n<=N) return mud[n];
    if(ans_mud[n]) return ans_mud[n];
    ll res=1ll;//卷积单项的时候n可以提出来 mud*id=e e的前缀和不可以将n提出来 对于每一项n不同 T_T
    for(ll l=2,r;l<=n;l=r+1)//这个n不是函数的输入变量n 而是卷积的第n项 所以卷积的前n项和是 1*e(1)+2*e(2)+3*e(3)+...n*e(n)=1
        r=n/(n/l),res-=(ll)cal(l,r)*f_mud(n/l)%mod,res%=mod;
    return ans_mud[n]=(res+mod)%mod;
}
inline int fenkuai_dd(ll n){
     //求出dd的前nn项和
    if(n<=N) return dd[n];
    ll res=0;
    for(ll l=1,r;l<=n;l=r+1)
        r=n/(n/l),res+=cal(l,r)*((n/l)%mod)%mod,res%=mod;
    return (res+mod)%mod;
}
inline int solve(ll n){
     //[l,r]内n/d相同 整体分块求 前半部分杜教筛[l,r]之间的mud的和 后半部分分块求[1,n/l]之间dd的和
    ll res=0;
    for(ll l=1,r;l<=n;l=r+1){
     
        r=n/(n/l);int _dd=fenkuai_dd(n/l);
        res+=(ll)(f_mud(r)-f_mud(l-1))%mod*_dd%mod*_dd%mod,res%=mod;
    }
    return (res+mod)%mod;
}
int main(){
     
    init();ll n;scanf("%lld",&n);
    printf("%d\n",solve(n));
}

51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第9张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第10张图片
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第11张图片51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第12张图片
51nod(1220 约数之和 推式子反演+线性筛+杜教筛)_第13张图片

你可能感兴趣的:(数学==杜教筛)