BZOJ(本校) 3027 快速傅里叶变换 - 概率与期望&dp

题目描述
有n 颗珠子,珠子的编号依次为1 到n。第i 颗珠子的美丽值为vi,这是一个在1 到m 之间的正整数。
查尔明将会从中等概率随机抽取1 到n 颗珠子,那么此时他的高兴度为所有抽到的珠子的美丽值的最大公约数。查尔明想知道,他的期望高兴度是多少,你能帮帮他吗?因为查尔明不喜欢实数和大数,所以你只需要输出结果×(2^n − 1) 的值对998244353 取模的结果即可。

输入
n, m
v1, v2, ……,vn

输出
答案

样例输入
3 4
2 4 3

样例输出
14

提示
对于30% 的数据,n ≤ 20,m ≤ 100000。
对于另外30% 的数据,n ≤ 100000,m ≤ 20。
对于100% 的数据,n ≤ 100000,m ≤ 100000。

来源
Claris

分析:

先求出1~m中,每个数出现的次数,记为a[]。
令f[i]表示选出的数所得的gcd是i的倍数的方案数,t为在给出的n个数中i的倍数出现的次数
则:f[i] = 2t -1
那么根据容斥原理,令g[i]表示选出的数所得的gcd是i的方案数
则:

g[i]=f[i]ji,1<=j<=mg[j]

ans=ni=1ig[i]

不要忘记%Mod哦,前面的推导都没有写%Mod

#include<cstdio>
#define MAXN 100000
#define Mod 998244353
typedef long long LL;

LL n,m,a[MAXN+10],f[MAXN+10],g[MAXN+10],P[MAXN+10],ans;

int main()
{
    LL x;
    scanf("%I64d%I64d",&n,&m);
    for(LL i=1;i<=n;i++){
        scanf("%I64d",&x);
        a[x]++;
    }
    P[0]=1;
    for(LL i=1;i<=n;i++)
        P[i]=P[i-1]*2%Mod;
    for(LL i=1;i<=m;i++){
        LL cnt=0;
        for(LL j=i;j<=m;j+=i)
            cnt+=a[j];
        f[i]=(P[cnt]-1)%Mod;
    }
    for(LL i=m;i>=1;i--){
        LL sum=0;
        for(LL j=i+i;j<=m;j+=i)
            sum=(sum+g[j])%Mod;
        g[i]=(f[i]-sum+Mod)%Mod;
    }
    for(LL i=1;i<=m;i++)
        ans=(ans+i*g[i]%Mod)%Mod;
    printf("%lld\n",ans);
    return 0;
}
posted @ 2016-02-16 23:11  KatarinaYuan  阅读(176)  评论(0编辑  收藏  举报