• 集合数数


    G - Array Partition

    题意:给你(n)个数,让求共有多少种,将这(n)个数分成两个集合,两个集合里的各自乘积的最小公倍数是(1)
    题解:我tm怎么可能会想到使用并查集,好久没用到了,就是用并查集将有公共质因数的存起来,然后就是可以知道一共有(x)个这样的乘积互质的集合数量,然后就考虑是从这(x)个中,分别拿出(1, 2, 3, ··· x-1)个放入第一个集合,然后就是(2^{x}-2),考虑到可以反转,那就得( imes 2)但是由于这种取法是会包括翻转,因为假设当拿(1)放入第(1)个集合,然后后面也算了拿(2, 3, 4, ··· x-1)放入第一个集合,所以就是正好的翻转,就不用( imes 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();
    	}
    } 
    
    
  • 相关阅读:
    RAID介绍,RAID5,10制作与损坏恢复
    ELK 安装过程
    centos 系统 yum安装软件报错
    linux系统磁盘分区
    python实现遍历两个文件夹,比对文件异常,生成比对报告功能
    win10新装系统,显卡风扇转动,链接正常开机,但设备管理器如果显示,无法更新驱动
    navicat premium 破解,无限试用方法
    安装vmware workstations 12 +ubuntu 遇到的一些问题
    win10 如何打开telnet,ftp等服务
    linux集群架构-keepalived高可用
  • 原文地址:https://www.cnblogs.com/Xiao-yan/p/14354765.html
Copyright © 2020-2023  润新知