CodeForces 585D Present for Vitalik the Philatelist(容斥原理+gcd)

来源:互联网 发布:安卓js css本地打包 编辑:程序博客网 时间:2024/06/05 05:33

题意:给出一个数字序列,求有多少组满足原来子集不互质,先加一个元素后新集合互质的集合数量。

思路:首先解决子问题,如何求出一个集合中互质的子集个数,首先求出I的倍数的元素的个数,记为cnt[I],

然后运用容斥原理来做,当I为某些不重复的素数的组合时,当质因数的个数为奇时,减去2^cnt[I]-1,反之则加。

如果I的质因数分解的结果中有重复的质因数的情况,那么不加也不减,因为I已经在之前被考虑过了。

然后求出来互质的子集的数量后,固定每个元素,求出剩下的不互质的子集中与这个元素互质的集合数量就是答案,

因为这道题卡空间,即使预处理出每个数的所有质因数也会被卡掉,所以可以用筛法先求出每个数的最小的质因数,

求每个数的所有不同质因数组合成的因数时,先求出每个数的所有质因数

然后用状压求出每个数的所有不同质因数组合成的因数。

#include <bits/stdc++.h>#define eps 1e-6#define LL long long#define pii pair<int, int>#define pb push_back#define mp make_pair//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;const int MAXN = 1000000;const int MAXM = 10001000;const int MOD = 1e9+7;//const int INF = 0x3f3f3f3f;int n;int a[MAXN], cnt[MAXM], mul[1000], c[MAXM];int sieve[MAXM];LL po[MAXN];void init(int m) {for (int i = 1; i <= m; i++) sieve[i] = i;for (int i = 2; i*i <= m; i++) if (sieve[i] == i) {for (int j = i*i; j <= m; j+=i) sieve[j] = i; }po[0] = 1;for (int i = 1; i <= n+10; i++) { po[i] = po[i-1]<<1;if (po[i] >= MOD) po[i] -= MOD;}}vector<pii> get_prime(int n) {vector<int> prime;while (n > 1) {int p = sieve[n];while (n%p == 0) {n /= p;}prime.push_back(p);}vector<pii> ans;int sz = prime.size();int maxS = 1 << sz;mul[0] = 1;for (int j = 0; j < sz; j++) mul[1<<j] = prime[j];for (int j = 1; j < maxS; j++) {mul[j] = mul[j&-j] * mul[j^(j&-j)];ans.push_back(mp(mul[j], __builtin_popcount(j)));}return ans;}int main(){//freopen("input.txt", "r", stdin);scanf("%d", &n);int maxA = 0;for (int i = 1; i <= n; i++) {scanf("%d", &a[i]);maxA = max(a[i], maxA);} init(maxA+10);for (int i = 1; i <= n; i++) {vector<pii> d = get_prime(a[i]);for (int j = 0; j < d.size(); j++) {cnt[d[j].first]++;c[d[j].first] = d[j].second;}}LL cop = po[n] - 1;for (int i = 2; i <= maxA; i++) {if (c[i]&1)cop = (cop-po[cnt[i]]+1) % MOD;else if (c[i] != 0)cop = (cop+po[cnt[i]]-1) % MOD;//cout << i << " " << d.size() << " " << cop << endl;}LL noCop = po[n] - 1 - cop;//cout << noCop << endl;LL ans = 0;for (int i = 1; i <= n; i++) {vector<pii> d = get_prime(a[i]);LL tmp = noCop;for (int j = 0; j < d.size(); j++) {if (d[j].second&1)tmp = (tmp-po[cnt[d[j].first]]+1) % MOD;else tmp = (tmp+po[cnt[d[j].first]]-1) % MOD;}ans = (ans + tmp) % MOD;//cout << ans << endl;}//cout << sieve[9] << endl;ans = (ans+MOD) % MOD;printf("%I64d", ans);return 0;}

0 0
原创粉丝点击