题意
给定一个数列
ai
,若子序列长度为
k
,最大公约数为
n≤2⋅105,ai≤106
,答案对
109+7
取模。
题解
考虑枚举
gcd
。设
cnt
是
gcd
的倍数的
ai
的个数。
当
gcd
是一个质数时,那么这个
gcd
的贡献即为
gcd⋅(1C1cnt+2C2cnt+⋯+cnt∗Ccntcnt)
由基础的组合数学知识得上式的结果为
gcd⋅(cnt⋅2cnt−1)
当 gcd 不是一个质数时,上式计算的贡献显然多了,它计算多的贡献是
∑x|gcdx⋅(cnt⋅2cnt−1)
如果直接枚举因子减去多出的贡献,复杂度 O(AA−−√) 的,不能接受。
从小到大枚举 gcd ,再将当前 gcd 的倍数都减去当前答案,或者预处理出 GCD[gcd]=gcd−∑x|gcdx ,类似埃拉托斯特尼筛法复杂度 O(AloglogA)
代码
/// by ztx
/// blog.csdn.net/hzoi_ztx
#include <bits/stdc++.h>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define rep(i,l,r) for(i=(l);i< (r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
#define rev(i,r,l) for(i=(r);i> (l);i--)
#define Each(i,v) for(i=v.begin();i!=v.end();i++)
#define r(x) read(x)
typedef long long ll ;
typedef double lf ;
int CH , NEG ;
template <typename TP>inline void read(TP& ret) {
ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
if (CH == '-') NEG = true , CH = getchar() ;
while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
if (NEG) ret = -ret ;
}
template<typename TP>inline bool MI(TP&a,const TP&b){return a>b?a=b,true:false;}
template<typename TP>inline bool MA(TP&a,const TP&b){return a<b?a=b,true:false;}
#define kN 200010LL
#define mod 1000000007LL
#define kA 1000010LL
inline void inc(int&a,const int&b) {a+=b;if(a>=mod)a-=mod;}
inline void dec(int&a,const int&b) {a-=b;if(a<0)a+=mod;}
int n, ans = 0, ma = 1;
int cnt[kA], pow_2[kN], gcd[kA];
int main() {
int i, j, now;
r(n);
Rep (i,1,n) r(j), cnt[j] ++ , MA(ma,j);
pow_2[0] = 1;
Rep (i,1,n) pow_2[i] = pow_2[i-1], inc(pow_2[i],pow_2[i-1]);
Rep (i,2,ma)
for (gcd[i]+=i, j=i<<1; j <= ma; j += i) dec(gcd[j],gcd[i]);
Rep (i,2,ma) {
for (now=0, j=i; j <= ma; j += i)
now += cnt[j];
if (!now) continue;
inc(ans,1LL*now*gcd[i]%mod*pow_2[now-1]%mod);
}
printf("%d\n", ans);
END: getchar(), getchar();
return 0;
}