CodeForces 839D Winter is here(数学 容斥)

题意:给你n个数,问你所有满足gcd>1的子集,每个子集贡献为子集内元素个数*子集gcd,问所有满足条件的集合的

献和。


思路:可以枚举gcd,计算每个gcd的贡献,设含因子i的个数为cnt[i], gcd为i的贡献个数为1*C(cnt[i], 1) + 2*C(cnt[i], 

2) 3*C(cnt[i], 3) ... + cnt[i]*C(cnt[i], cnt[i])) - i*2的贡献 - i*3的贡献...., 可以记为ans[i] = 2^(cnt[i]-1) - ans[i*2] - 

ans[i*3]. 倒着容斥下就可以,跟多校第二场的那题一样点击打开链接


代码:

#include
using namespace std;
typedef long long ll;
const int mod = 1e9+7;
const int maxn = 2e5+5;
const int maxm = 1e6+5;
ll num[maxm], fac[maxn] = {1, 2};

int main(void)
{
    int n;
    for(int i = 2; i < maxn; i++)
        fac[i] = fac[i-1]*2%mod;
    while(cin >> n)
    {
        memset(num, 0, sizeof(num));
        for(int i = 1; i <= n; i++)
        {
            int x;
            scanf("%d", &x);
            num[x]++;
        }
        for(int i = 2; i < maxm; i++)
            for(int j = i*2; j < maxm; j+=i)
                num[i] += num[j];
        for(int i = 2; i < maxm; i++)
            num[i] = fac[num[i]-1]*num[i]%mod;
        ll ans = 0;
        for(int i = maxm-1; i >= 2; i--)
            for(int j = i*2; j < maxm; j+=i)
                num[i] -= num[j];
        for(int i = 2; i < maxm; i++)
            ans = (ans+num[i]*i)%mod;
        printf("%I64d\n", ans);
    }
    return 0;
}


你可能感兴趣的:(组合数学)