【CodeForces】915 G. Coprime Arrays 莫比乌斯反演

【题目】G. Coprime Arrays

【题意】当含n个数字的数组的总gcd=1时认为这个数组互质。给定n和k,求所有sum(i),i=1~k,其中sum(i)为n个数字的数组,每个数字均<=i,总gcd=1的方案数。n<=2*10^6。答案将所有sum(i)处理成一个数字后输出。

【算法】数论(莫比乌斯反演)

【题解】假设当前求sum(k),令f(i)表示gcd=i的数组方案数,F(i)表示i|gcd的数组的方案数。

因为F(x)=Σx|df(d),由莫比乌斯反演定理,f(x)=Σx|dμ(d/x)*F(d)。

又F(x)=(k/x)^n,所以f(1)=Σμ(d)*(k/d)^n,d=1~k

初始k=1,当k++时ans+=Σd|kμ(d)*((k/d)^n-(k/d-1)^n),这个过程只需要k ln k枚举贡献答案即可,同时预处理快速幂。

复杂度O(k log n+k ln k)。

#include<cstdio>
const int N=2000010,MOD=1e9+7;
int n,m,miu[N],prime[N],mark[N],sum[N],p[N],tot,ans,ANS;
int pow(int x,int k){
    if(!x)return 0;
    int ans=1;
    while(k){
        if(k&1)ans=1ll*ans*x%MOD;
        x=1ll*x*x%MOD;
        k>>=1;
    }
    return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    miu[1]=1;
    for(int i=2;i<=m;i++){
        if(!mark[i]){miu[prime[++tot]=i]=-1;}
        for(int j=1;j<=tot&&i*prime[j]<=m;j++){
            mark[i*prime[j]]=1;
            if(i%prime[j]==0)break;
            miu[i*prime[j]]=-miu[i];
        }
    }
    for(int i=0;i<=2000000;i++)p[i]=pow(i,n);
    for(int i=1;i<=m;i++){
        for(int j=i;j<=m;j+=i)sum[j]=((sum[j]+1ll*miu[i]*(p[j/i]-p[j/i-1]))%MOD+MOD)%MOD;
        ans=(ans+sum[i])%MOD;
        ANS=(ANS+(ans^i))%MOD;
    }
    printf("%d",ANS);
    return 0;
}
View Code

 

posted @ 2018-01-15 16:39  ONION_CYC  阅读(440)  评论(0编辑  收藏  举报