Codeforces 839 D. Winter is here 容斥

来源:互联网 发布:手机ui界面设计软件 编辑:程序博客网 时间:2024/06/05 10:18

传送门:Codeforces 839D

题意:给出一个序列,求取出一个字序列,当他们的GCD大于1时,将贡献子序列所有数的gcd * 子序列的长度,问总贡献是多少。

思路:感觉很像前几次的多校一个题,但是想了很久也没想出来该怎么求∑i∗C(n, i)(i >= 1)

然而,其实∑i∗C(n, i) == n * ∑ C(n - 1, i - 1)(i >= 0),化成组合数的定义式立马就能看出来。。

这样∑i∗C(n, i) == n * 2 ^ (n - 1).  然后我们枚举gcd的大小,能产生i当gcd的序列中必定都是i的倍数,因此我们只需要统计i的倍数有多少个,然后利用上面的式子计算,很容易发现有重复计算的部分,倒着容斥一遍就行了,最后再乘以个i加到答案里即可。

膜拜大佬17行ac代码:点击打开链接  题解也很言简意赅,不过稍微有点瑕疵:ans[i] = f[i] - f[2i] - f[3i]...

还有莫比乌斯的题解思路:点击打开链接

代码:

#include<bits/stdc++.h>#define ll long longusing namespace std;const int MAXN = 1000010;const int mod = 1e9 + 7;int cnt[MAXN], u[MAXN], f[MAXN];int main(){    int n, t, up = 0;    cin >> n;    for(int i = 0; i < n; i++)    {        scanf("%d", &t);        cnt[t]++;        up = max(up, t);    }    u[0] = 1;    for(int i = 1; i <= up; i++)    u[i] = (2 * u[i - 1]) % mod;    ll ans = 0;    for(int i = up; i >= 2; i--)//逆序求解,因为可以顺便进行容斥    {        int tmp = i, k = 0;        while(tmp <= up) k += cnt[tmp], tmp += i;        if(k == 0) continue;        f[i] = (1ll * k * u[k - 1]) % mod;        for(int j = i + i; j <= up; j += i)        f[i] = (f[i] - f[j] + mod) % mod;        ans = (ans + 1ll * i * f[i]) % mod;    }    cout << ans << endl;}


原创粉丝点击