码迷,mamicode.com
首页 > 其他好文 > 详细

[暴力统计] zoj 3868 GCD Expectation

时间:2015-04-13 12:55:04      阅读:115      评论:0      收藏:0      [点我收藏+]

标签:

题意:

给n和k,求n个数的任意非空子集gcd的k次方的期望。

最后期望乘上2^n-1

思路:

因为取每个子集都是等概率,所以取出每个子集的概率是1/(2^n-1)

然而最后的答案是乘上2^n-1

所以其实求的就是每个非空子集的gcd的k次方的和。

然后就是求法了。

我们可以把题目转换成求gcd等于i的非空集合有多少个。

gcd从Max枚举到1,求出答案。

对于每个i,设n个数中是i的倍数的数有x个。

那么gcd等于i的个数就是总共的 (2^x-1)个减去gcd等于j的个数,j是i的倍数。

因此要从大到小过一遍。

代码:

#include"stdio.h"
#include"algorithm"
#include"string.h"
#include"iostream"
#include"queue"
#include"map"
#include"string"
#define mod 998244353
#define ll long long
using namespace std;
int sum[2002000],a[1234567];
int dp[2002000];
ll power(ll a,int k)
{
    ll b=1;
    while(k)
    {
        if(k&1) b=(b*a)%mod;
        a=(a*a)%mod;
        k/=2;
    }
    return b;
}
int main()
{
    int t;
    cin>>t;
    memset(sum,0,sizeof(sum));
    while(t--)
    {
        int n,k,Max=0;
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            Max=max(a[i],Max);
            sum[a[i]]++;
        }
        for(int i=0;i<=Max;i++) dp[i]=0;
        ll ans=0;
        for(int i=Max;i>=1;i--)
        {
            int tep=0;
            for(int j=i;j<=Max;j+=i)
            {
                tep+=sum[j];
                dp[i]=(dp[i]-dp[j]+mod)%mod;
            }
            dp[i]=((dp[i]+power(2,tep)-1)%mod+mod)%mod;
            ans=(ans+dp[i]*power(i,k))%mod;
        }
        for(int i=0;i<n;i++) sum[a[i]]--;  //减少每次memset的时间
        printf("%lld\n",ans);
    }
    return 0;
}


[暴力统计] zoj 3868 GCD Expectation

标签:

原文地址:http://blog.csdn.net/wdcjdtc/article/details/45023591

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!