Codeforces Round #428 (Div. 2) D. Winter is here 数学

链接:

http://codeforces.com/contest/839/problem/D

题意:

给出一些数,求取出一些数,当他们的GCD大于0时,将数量乘GCD累加到答案上,求累加和。

题解:

这道题比赛的时候忘了考虑重复了,wa掉之后发现可能会出现重复,然而又不会写了。。

这道题需要知道一个公式就是 1*C(n,1)+2*C(n,2)+3*C(n,3)+...+n*C(n,n) = n*2^(n-1)

我们枚举GCD,统计为其倍数的数字数量,先假定其能组成的集合数为贡献,

但是我们发现在统计的过程中有多余统计的部分,比如4和8是2的倍数,

然而它们的GCD等于4,所以我们对于每个集合数的贡献要减去所有其倍数的集合数的贡献,

倒着容斥即可。

代码:

31 int n;
32 int a[MAXN], dp[MAXN], pw[MAXN], mx;
33 
34 int main() {
35     ios::sync_with_stdio(false), cin.tie(0);
36     pw[0] = 1;
37     rep(i, 1, MAXN) pw[i] = 2 * pw[i - 1] % MOD;
38     cin >> n;
39     rep(i, 0, n) {
40         int x;
41         cin >> x;
42         a[x]++;
43         mx = max(mx, x);
44     }
45     int ans = 0;
46     for (int i = mx; i > 1; i--) {
47         int t = 0;
48         for (int j = i; j <= mx; j += i) t += a[j];
49         if (!t) continue;
50         dp[i] = 1LL * t*pw[t - 1] % MOD;
51         for (int j = 2 * i; j <= mx; j += i) 
52             dp[i] = (dp[i] - dp[j] + MOD) % MOD;
53         ans = (ans + 1LL * dp[i] * i) % MOD;
54     }
55     cout << ans << endl;
56     return 0;
57 }

 

posted @ 2017-08-13 21:54  Flowersea  阅读(160)  评论(0编辑  收藏  举报