题意
给你n个数
然后定义一个团队为选出若干个数,使得他们gcd不为1
然后一个团队的价值为,他们所有数的gcd乘上他们的人数
然后要你算出所有有可能的团队的和
题解
挺神的一道题。。反正我是不怎么会了。。要嘎爷爷带飞
然后怎么做呢?
我们考虑答案是怎么算的:
Ans=∑i∗gcd为i的长度∗gcd为这个长度的个数
我们用一个数组,sum[i]表示gcd为i个序列长度和个数的总和
不难知道,答案就是
∑i∗sum[i]
那么怎么算出这个sum[i]呢
先假设一个有公因数i的情况吧。。
我们定义,cnt[i]为有因数i的个数
然后可以得到
sum[i]=∑u=1cnt[i]Cucnt[i]∗u
sum[i]=∑u=1cnt[i]cnt[i]!(cnt[i]−u)!(u−1)!
把一个cnt[i]提出来
sum[i]=∑u=1cnt[i]cnt[i]∗(cnt[i]−1)!(cnt[i]−u)!(u−1)!
我们可以发现,右式又形成了一个组合数。。公式太麻烦,不想打了
于是用二项式定义化简可得
sum[i]=cnt[i]∗2cnt[i−1]
然后当然,这有许多多算的,就是说i吧i的倍数也算上了,所以要减去他的倍数
于是就做完了
CODE:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long LL;
const LL MOD=1e9+7;
const LL N=200005;
const LL M=1000005;
LL n;
LL s[N];
LL cnt[M];//这个因数有多少个人有
bool in[M];
LL f[M];
LL get (LL x,LL y)
{
if (y==1) return x;
if (y==0) return 1;
LL lalal=get(x,y/2);
lalal=lalal*lalal%MOD;
if (y&1) lalal=lalal*x%MOD;
return lalal;
}
LL dfs (LL x)
{
if (in[x]==true) return f[x];
in[x]=true;
if (cnt[x]==0) {f[x]=0;return 0;}
LL lalal=0;
for (LL i=2;i*x<=1000000;i++)
{
lalal=lalal+dfs(i*x);
if (lalal>=MOD) lalal-=MOD;
}
f[x]=((cnt[x]*get(2,cnt[x]-1)%MOD-lalal)%MOD+MOD)%MOD;
return f[x];
}
int main()
{
memset(in,false,sizeof(in));
scanf("%lld",&n);
for (LL u=1;u<=n;u++) scanf("%lld",&s[u]);
for (LL u=1;u<=n;u++)
{
for (LL i=2;i*i<=s[u];i++)
if (s[u]%i==0)
{
cnt[i]++;
if (i*i!=s[u]) cnt[s[u]/i]++;
}
cnt[s[u]]++;
}
for (LL u=2;u<=1000000;u++) dfs(u);
LL ans=0;
for (LL u=2;u<=1000000;u++) ans=(ans+u*f[u]%MOD)%MOD;
printf("%lld\n",ans);
return 0;
}