Codeforces 839D Winter is here

来源:互联网 发布:win7电脑桌面美化软件 编辑:程序博客网 时间:2024/06/04 23:42

转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents

题意

给一个长度为n(1n200000)序列a(1ai1000000),对于某个子序列ai1ai2ai3aik,长度为k,其中i1<i2<i3<<ik,如果gcd(ai1ai2ai3aik)>1,则称这个子序列为一个clan,这个clan的strength为kgcd(ai1ai2ai3aik),求所有的clan的strength之和

思路

枚举gcd的值x,对于每一个x,统计一下在序列中有多少个元素时x的倍数,这里可以开一个桶,将读入序列存入,这样可以将复杂度降至O(nlog(n)),设有m个元素是x的倍数,则这些元素对答案的贡献为

x×[1×C1m+2×C2m++m×Cmm]

这个式子的值为xm2m1
但是这样还有一个问题就是,比如说x=2时,假设数列中有元素4、8,这样4和8的gcd为4而不是2,我们应该想办法去掉这种情况具体做法如下:
在枚举到x的时候,我们统计出m,计算出m2m1后,应该枚举x的倍数减去相应的值,这就要求我们在枚举x的时候需要倒着枚举,这样才能保证我们枚举到x的时候,x的倍数都已经计算过了


具体代码如下:
Result:Accepted    Memory: 13600 KB   Time : 249 ms

#include<cstdio>const int maxn=1e6+5;const int mod =1e9+7;int n,x,ans;int pow[maxn],a[maxn],f[maxn];int main(){    scanf("%d",&n);    pow[0] = 1;    for(int i=1; i<=n; i++)        pow[i]=2*pow[i-1]%mod;    for(int i=1; i<=n; i++)    {        scanf("%d",&x);        a[x]++;    }    for(int i=maxn-1; i>1; i--)    {        x = 0;        for(int j=i; j<maxn; j+=i)            x+=a[j];        if(x)        {            f[i]=1LL*x*pow[x-1]%mod;            for(int j=i+i; j<maxn; j+=i)                f[i]=(f[i]-f[j]+mod)%mod;            ans=(1LL*f[i]*i+ans)%mod;        }    }    printf("%d",ans);}
原创粉丝点击