转载请注明出处,谢谢http://blog.csdn.net/bigtiao097?viewmode=contents
题意:
给一个长度为n (1≤n≤200000) 序列a (1≤ai≤1000000) ,对于某个子序列 ai1、ai2、ai3……aik ,长度为k,其中 i1<i2<i3<……<ik ,如果 gcd(ai1、ai2、ai3……aik)>1 ,则称这个子序列为一个clan,这个clan的strength为 k⋅gcd(ai1、ai2、ai3……aik) ,求所有的clan的strength之和
思路:
枚举gcd的值x,对于每一个x,统计一下在序列中有多少个元素时x的倍数,这里可以开一个桶,将读入序列存入,这样可以将复杂度降至 O(nlog(n)) ,设有m个元素是x的倍数,则这些元素对答案的贡献为
x×[1×C1m+2×C2m+……+m×Cmm]
这个式子的值为 x∗m∗2m−1
但是这样还有一个问题就是,比如说x=2时,假设数列中有元素4、8,这样4和8的gcd为4而不是2,我们应该想办法去掉这种情况具体做法如下:
在枚举到x的时候,我们统计出m,计算出 m∗2m−1 后,应该枚举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);
}