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 }