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

被折叠的 条评论
为什么被折叠?



