51nod1220约数之和

来源:互联网 发布:网络推广有几种方法 编辑:程序博客网 时间:2024/05/17 08:48

51nod1220约数之和

Time Limit 3s Memory Limit 128KB
Description
σ(x)表示x的约束和
ni=1nj=1σ(ij)
Input
一个数n(0<n109)
Output
一个数答,对109+7取模。
Sample Input

1000

Sample Output

576513341

解题思路

莫比乌斯反演,杜教筛的各种技能
定义[x]的取值为1(x为真)否则为0

Ans=i=1nj=1nd|ijd

d|ij能不能化为一个d|j呢,想到d|ij等同于dgcd(i,d)|j

d|ij要满足xy=d[x|i][y|j],x取gcd(i,d)能供给完[x|i]也就是说,这时gcd(y,i)=1当且仅当y|jd|ij成立,即d|ijdgcd(i,d)|j

Ans=i=1nj=1nd=1ijd[dgcd(i,d)|j]=i=1nd=1indngcd(i,d)d=d=1ni=1nd=1in[gcd(i,d)=d]dndd      (dgcd(i,d))

gcd(i,d)=d?
考虑化为gcd(,)=1很简单啊,用idd代替i,用ddd代替d

Ans=d=1nid=1nddd=1idn[gcd(id,dd)=1]dddddn

用i代替id,用d代替dd
Ans=d=1ni=1ndd=1in[gcd(i,d)=1]ddnd=d=1ndi=1ndd=1n[gcd(i,d)=1]dnd=i=1nd=1nidd=1n[gcd(i,d)=1]dnd=i=1n12ni(ni+1)d=1n[gcd(i,d)=1]dnd

gcd(i,d)=1怎么处理呢,想到d|nμ(d)=[n=1]那么
[gcd(i,d)=1]=k|gcd(i,d)μ(k)=k[k|i][k|d]μ(k)


Ans=i=1n12ni(ni+1)d=1ndndd=1n[d|i][d|d]μ(d)=d=1nμ(d)id=1ndiddnidddd=1nd12nddd(nddd+1)=d=1ndμ(d)i=1ndinidd=1nd12ndd(ndd+1)


f(x)=xμ(x)

g(x)=i=1xixi

h(x)=i=1x12xi(xi+1)

其实h和g是等价的

i=1x12xi(xi+1)=i=1xj=1xij(ij)=i=1xj=1xii=i=1xxii


Ans=d=1nf(d)g(nd)h(nd)=d=1ng(nd)2f(d)

我们想,nd只有2n

i<=n时,i[1,n]
i>n时,ni<n
ni只有2n
对于i,有j=max{x|nx=ni}=nni

所以,分块处理
ij[nni1+1,nni]nj=i
只需维护s(x)=xi=1f(x)即可,g(ni)直接算
O(n)=niO(ni)=O(n34)

对于S(x)
d|nμ(d)=[n=1]
那么

1=i=1nid|iμ(d)=d=1ni=1niidμ(d)=d=1ni=1nidiμ(i)=d=1ndi=1nif(i)=d=1nds(nd)

s(n)=1d=2nds(nd)(d=1)

同样,分块处理n4=n22,所以直接搜会有很多重复的项,哈希判重,O(n)=niO(ni)=o(n34)
预处理前n23项,复杂度可降到O(n23)

总复杂度O(n34)

#include<cstring>#include<cstdio>#include<cctype>#define N 3001001#define lim 43007#define mo 1000000007#define ny 500000004using namespace std;typedef long long ll;ll n,s[N],sum[lim],hash[lim],mu[N],pr[N];bool bz[N];int get(ll x){    int y=(int)(x%lim);    while(hash[y] && hash[y]!=x)y++,y=y==lim?0:y;return y;}ll S(ll a){    if(a<N)return s[a];    int x=get(a);    if(hash[x])return sum[x];    hash[x]=a;ll ans=1;    for(ll i=2,j;i<=a;i=j+1){        j=a/(a/i);        ans=(ans-(j+i)%mo*((j-i+1)%mo)%mo*ny%mo*S(a/i)%mo+mo)%mo;    }sum[x]=ans;return ans;}ll g(ll a){    ll ans=0;    for(ll i=1,j;i<=a;i=j+1){        j=a/(a/i);        ans=(ans+a/i%mo*((i+j)%mo*((j-i+1)%mo)%mo*ny%mo))%mo;    }return ans;}int main(){    s[1]=mu[1]=1;    for(ll i=2;i<N;i++){        if(!bz[i])mu[pr[++pr[0]]=i]=-1;        s[i]=(s[i-1]+mu[i]*i%mo+mo)%mo;        for(int j=1;j<=pr[0] && i*pr[j]<N;j++){            bz[i*pr[j]]=1;mu[i*pr[j]]=-mu[i];            if(i%pr[j]==0){mu[i*pr[j]]=0;break;}        }    }    scanf("%lld",&n);    ll ans=0;    for(ll i=1,j,las=0,now,t;i<=n;i=j+1,las=now){        j=n/(n/i);now=S(j);t=g(n/i);        ans=(ans+(now-las+mo)%mo*t%mo*t%mo)%mo;    }    printf("%lld",ans);}
原创粉丝点击