集合数数

G - Array Partition

题意:给你\(n\)个数,让求共有多少种,将这\(n\)个数分成两个集合,两个集合里的各自乘积的最小公倍数是\(1\)
题解:我tm怎么可能会想到使用并查集,好久没用到了,就是用并查集将有公共质因数的存起来,然后就是可以知道一共有\(x\)个这样的乘积互质的集合数量,然后就考虑是从这\(x\)个中,分别拿出\(1, 2, 3, ··· x-1\)个放入第一个集合,然后就是\(2^{x}-2\),考虑到可以反转,那就得\(\times 2\)但是由于这种取法是会包括翻转,因为假设当拿\(1\)放入第\(1\)个集合,然后后面也算了拿\(2, 3, 4, ··· x-1\)放入第一个集合,所以就是正好的翻转,就不用\(\times 2\)了。
代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
#include <queue>
#include <cmath>
#include <set>
using namespace std;
typedef long long ll;
const int N = 1e6 + 99;
const ll mod = 1e9 + 7;
ll pr[N], pr_cnt;
bool vis[N];
void init() {
	for (int i = 2; i < N; i++) {
		if (!vis[i]) pr[++pr_cnt] = i;
		for (int j = 1; i  * pr[j]< N; j++) {
			vis[i * pr[j]] = 1;
			if (i % pr[j] == 0)break;
		}
	}
}
ll q_mi(ll a, ll k, ll mod) {
	ll ret = 1;
	ll x = a;
	while (k) {
		if (k & 1) (ret *= x) %= mod;
		k >>= 1;
		(x *= x) %= mod;
	}
	return ret;
}

ll a[N];
vector<ll>G[N];
ll pr_fac_cnt[N];
set<ll>se;
ll f[N];
ll Find(ll x) {return f[x] == x?x:f[x] = Find(f[x]);}
void solve() {
	ll n;
	cin >> n;
	ll ans = 0;
	for (ll i = 1; i <= n; i++) {
		cin  >> a[i];
		ll num = a[i];
		for (ll j = 1; j <= pr_cnt && pr[j] * pr[j] <= num; j++) {
			ll prime = pr[j];

			if (num % prime == 0) {
				G[pr[j]].push_back(i);
				pr_fac_cnt[prime]++; 
				while ( num % prime == 0) num /= prime;
			}
		}
		if (num != 1)  {
			pr_fac_cnt[num]++; 
			G[num].push_back(i);
		}		
	} 
	for (ll i = 1; i <= n; i++)f[i] = i;
	for (ll i = 1; i <= pr_cnt; i++) {
		if (pr_fac_cnt[pr[i]]) {
			ll u = pr[i];
			for (ll i = 1; i < G[u].size(); i++) {
				ll fx = Find(G[u][i-1]);
				ll fy = Find(G[u][i]);
				if (fx != fy) {
					f[fx] = fy;
				}
			}
		}
	}
	for (ll i = 1; i <= n; i++) {
		se.insert(Find(i));
	}
	cout << (q_mi(2, se.size(), mod) - 2 + mod )%mod   << endl;
	se.clear();
	for (ll i = 1; i < N; i++) {
		G[i].resize(0);
		pr_fac_cnt[i] = 0;
	}
}
signed main() {
	ll t = 1;
	init();
	ios::sync_with_stdio(0);
	cin >> t;
	while (t--) {
		solve();
	}
} 

posted @ 2021-02-01 00:01  u_yan  阅读(74)  评论(0编辑  收藏  举报