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

枚举GCD算法解析
本文介绍了一种解决特定组合数学问题的算法——通过枚举最大公约数(GCD)来计算满足条件的所有子集贡献总和。算法首先统计每个可能的最大公约数出现的次数,并利用这些计数来计算所有符合条件子集的贡献总和。

题意:给你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<bits/stdc++.h>
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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值