最后johsnows做jonsnow的题tle在了39...大概是因为我是假的snow吧。
这个题的想法挺套路的。
想法就是去枚举倍数,看有多少个数是当前这个数的倍数,这些数的gcd一定是当前这个数的倍数,假设有n个数,题目所求为gcd*k,枚举1<=i<=k,求出所有的C(i, n)*i,最后容次以下,去掉gcd是自己倍数的情况,就是以当前数位gcd的答案/gcd,容次之后乘回gcd就可以了。
注意求1-n的i*C(i,n)需要求一下公式,不能暴力求。
先把C(i,n)拆成阶乘的形式,就可以看出来i*C(i,n)就是n*(i-1, n-1),所以最后求和就是n*2^(n-1)了。
也可以考虑求导。原式=[(1+x)^n]'=n(1+x)^(n-1)。
代码:
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL maxn=1e6+5;
const int mod=1e9+7;
int book[maxn];
LL a[maxn+5];
LL b[maxn];
LL c[maxn];
LL dp[maxn];
LL mmm;
long long pw(long long a, long long b)
{
long long sum=1,base=a;
while(b)
{
if(b&1)sum=(sum*base)%mod;
base=(base*base)%mod;
b>>=1;
}
return sum;
}
void init()
{
LL i, j;
a[0]=1;
for(i=1; i<=200005; i++)
{
a[i]=(a[i-1]*i)%mod;
}
}
long long C(int m,int n)
{
long long sum=a[n];
// printf("%lld\n", sum);
sum=sum*pw(a[n-m],mod-2)%mod;
sum=sum*pw(a[m],mod-2)%mod;
return sum;
}
int main()
{
int n;
cin>>n;
int i, j;
LL ma=0;
for(i=0; i<n; i++)
{
scanf("%lld", &b[i]);
ma=max(ma, b[i]);
book[b[i]]++;
}
memset(dp, -1, sizeof dp);
LL ans=0;
init();
for(i=2; i<=ma; i++)
{
LL sum=0;
for(j=i; j<=ma; j+=i)
{
sum+=book[j];
}
// printf("%d %lld\n", i, sum);
LL g=i, y, z=0;
int x=i;
if(dp[sum]!=-1)
{
c[x]=(c[x]+dp[sum])%mod;
continue;
}
if(sum==0)continue;
z=(sum*pw(2LL, sum-1LL))%mod;
c[x]=(c[x]+z)%mod;
dp[sum]=z;
}
for(LL i=ma; i>=2; i--)
{
for(j=i+i; j<=ma; j+=i)
{
c[i]-=c[j], c[i]=(c[i]%mod+mod)%mod;
}
ans=(ans+(c[i]*i)%mod)%mod;
}
printf("%lld\n", ans);
}