Codeforces 839 D. Winter is here 容斥

传送门: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 long
using 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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值