【數學 並查集】X
阿新 • • 發佈:2020-08-13
題意
給出n個數,將它們劃分成2個集合,求出gcd(第1個集合的乘積,第2個集合的乘積)=1的劃分方案有多少種。
思路
如果2個數的gcd!=1那麼它們就必須同屬1個集合。
對於每個數的質因子,將它們放在一個聯通塊中,代表含有這些質因子的數都要屬於同一個集合。
如果數字可以放在任意一個集合,答案為2n-2,所以gcd=1答案為2聯通塊的個數-2
程式碼
#include <cstdio> #include <algorithm> const int MOD = 1e9 + 7; int t, n, cnt; int prime[1000001], v[1000001], oo[1000001], fa[1000001]; int find(int x) { return fa[x] = fa[x] == x ? x : find(fa[x]); } int power(int a, int b) { int res = 1; for (; b; b >>= 1) { if (b & 1) res = (long long)res * a % MOD; a = (long long)a * a % MOD; } return res; } int main() { scanf("%d", &t); for (int i = 2; i <= 1000000; i++) { if (!v[i]) { v[i] = i; prime[++cnt] = i; } for (int j = 1; j <= cnt; j++) { if (prime[j] > v[i] || prime[j] > 1000000 / i) break; v[i * prime[j]] = prime[j]; } } for (int a; t; t--) { int tot = 0; scanf("%d", &n); for (int i = 1; i <= 1000000; i++) fa[i] = i; oo[0] = 0; for (int i = 1; i <= n; i++) { scanf("%d", &a); if (a == 1) tot++; int last = 0; while (a >= 2) { int xx = v[a]; while (a % xx == 0) a /= xx; oo[++oo[0]] = xx; if (last) { int f1 = find(last), f2 = find(xx); fa[f2] = f1; } last = xx; } } std::sort(oo + 1, oo + oo[0] + 1); int m = std::unique(oo + 1, oo + oo[0] + 1) - (oo + 1); for (int i = 1; i <= m; i++) if (fa[oo[i]] == oo[i]) tot++; printf("%d\n", power(2, tot) - 2); } }