Codeforces Round #441 (Div. 2) D

来源:互联网 发布:ios付费软件推荐 编辑:程序博客网 时间:2024/05/22 08:27

题意

给你n个数
然后定义一个团队为选出若干个数,使得他们gcd不为1
然后一个团队的价值为,他们所有数的gcd乘上他们的人数
然后要你算出所有有可能的团队的和

题解

挺神的一道题。。反正我是不怎么会了。。要嘎爷爷带飞
然后怎么做呢?
我们考虑答案是怎么算的:

Ans=igcdigcd

我们用一个数组,sum[i]表示gcd为i个序列长度和个数的总和
不难知道,答案就是
isum[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)!(u1)!

把一个cnt[i]提出来
sum[i]=u=1cnt[i]cnt[i](cnt[i]1)!(cnt[i]u)!(u1)!

我们可以发现,右式又形成了一个组合数。。公式太麻烦,不想打了
于是用二项式定义化简可得
sum[i]=cnt[i]2cnt[i1]

然后当然,这有许多多算的,就是说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;}
原创粉丝点击