前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Zoj 3868 GCD Expectation

Zoj 3868 GCD Expectation

作者头像
若羽
发布2019-07-15 16:34:47
3630
发布2019-07-15 16:34:47
举报
文章被收录于专栏:Code思维奇妙屋Code思维奇妙屋

给一个集合,大小为n , 求所有子集的gcd 的期望和 。 

期望的定义为 这个子集的最大公约数的K次方 ; 

每个元素被选中的概率是等可能的

即概率 p = (发生的事件数)/(总的事件数);

总的事件数 = 2^n -1; 大小为n的集合的非空子集个数为2^n -1

期望 = p(i) *i;  

       = 1*p(1) + 2*p(2) + ... +n*p(n);

设x发生的事件数为 dp[x] , 则上式可化简为:

       =1*dp[1]/(2^n-1) + 2*dp[2]/(2^n-1) + ... +n*dp[n]/(2^n-1);

       =1/(2^n-1)*(1*dp[1] + 2*dp[2] + ... + n*dp[n]);

题目要求最后所得结果乘以 (2^n-1);

所以式子最后化简为:1*dp[1] + 2*dp[2] + ... + n*dp[n]

即问题转化为求gcd = i 的子集数

假设gcd = m*i (m = 0,1,2,3,... && m*i <= max_num)的个数为dp[i]个

那么gcd = i 的个数则为 for(int j= i + i ; j <= max_num ; j += i) dp[i]-=dp[j] ;

则期望为:dp[1] * 1^k + dp[2] * 2^k + ... dp[i] * i^k ;

代码语言:javascript
复制
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cstdlib>
 4 #include <cmath>
 5 #include <iostream>
 6 #include <map>
 7 #include <list>
 8 #include <queue>
 9 #include <stack>
10 #include <string>
11 #include <algorithm>
12 #include <iterator>
13 using namespace std;
14 #define MAXN 1000010
15 #define INF 0x3f3f3f3f
16 #define MOD 998244353
17 #define eps 1e-6
18 #define LL long long 
19 int num[MAXN];
20 LL dp[MAXN];
21 //dp[i] = 2^x -1 ; gcd = n*i;
22 //for(int j = i ; j <= max_num ; j += i) dp[i] -= dp[j];
23 LL qpow(LL x , LL k)
24 {
25     LL res=1;
26     while(k)
27     {
28         if(k & 1) res = res * x % MOD;
29         x = x * x % MOD;
30         k >>= 1;
31     }
32     return res;
33 }
34 
35 int main()
36 {
37     int T;
38     int n,k;
39     LL ans;
40     scanf("%d",&T);
41     while(T--)
42     {
43         scanf("%d %d",&n,&k);
44         int x;
45         int max_num = 0;
46         int cunt = 0;
47         memset(num , 0 , sizeof(num));
48         memset(dp , 0 , sizeof(dp));
49         for(int i = 0 ; i < n ; i ++)
50         {
51             scanf("%d",&x);
52             num[x] ++;
53             max_num = max(x , max_num);
54         }
55 
56         ans = 0;
57         for(int i = max_num ; i >= 1 ; i --)
58         {
59             cunt = 0;
60             dp[i] = 0;
61             for(int j = i ; j <= max_num ; j += i)
62             {
63                 cunt += num[j];
64                 if(j > i) dp[i] = (dp[i] - dp[j] + MOD) % MOD;
65             }
66             dp[i] = (dp[i] + qpow(2 , cunt) - 1 + MOD) % MOD;
67             ans = (ans + (dp[i] * qpow(i , k)) % MOD ) % MOD;
68         }
69         printf("%d\n",(int)ans);
70     }
71     return 0;
72 }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2015-04-18 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档