集合劃分 partition.cpp

【一句話題意】給定一個包含N 個非負整數的集合A,請將A 分成兩個子集P、Q,且使得gcd(ΠPiΠQi)==1gcd(\Pi P_i \Pi Q_i)==1。請計算這樣的劃分方法總數mod1000000007 後的值。 n<=1e6

【分析】一道可做的數論題。按質因數劃分,P和Q中不能有相同的質因數,擁有相同質因數的數必須放在同一個集合。將每個數分解質因數後,將每個數和質因數之間連一個雙向邊,顯然的是每個連通塊都必須放在同一個集合。考慮方案時,從1到n-1枚舉放入集合P的連通塊的組合方案數就是C1n+C2n+.....+Cn1nC^n_1+C^n_2+.....+C^n_{n-1}
這裏有個小技巧:C0n+C1n+......+Cn1n+Cnn=2nC^n_0+C^n_1+......+C^n_{n-1}+C^n_n=2^n(每個數都有選或不選兩種情況)
所以方案數就是2n-2

【code】

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rint register int
using namespace std;
const int maxn=1e5+100;
const int N=1e6+100;
const int mod=1e9+7;
int n,a[maxn];

int fac[N],prime[N],cnt;
struct Prime{
	int id,nxt;
}p1[maxn*18];
int h1[N],u1[N],tot1;

struct node{
	int id,nxt;
}p2[maxn*18];
int h2[maxn],u2[maxn],tot2;
inline void read(int &x){
	x=0;char tmp=getchar();
	while(tmp<'0'||tmp>'9') tmp=getchar();
	while(tmp>='0'&&tmp<='9') x=(x<<1)+(x<<3)+tmp-'0',tmp=getchar();
}
void prework(){
	for(int i=2;i<=1e6;i++){
		if(!fac[i]) fac[i]=++cnt,prime[cnt]=i;
		for(int j=1;i*prime[j]<=1e6&&j<=cnt;j++){
			fac[i*prime[j]]=j;
			if(j==fac[i]) break;
		}
	}
}
inline void add_p1(int x,int y){
	p1[tot1].id=y;
	p1[tot1].nxt=h1[x];
	h1[x]=tot1++;
}
inline void add_p2(int x,int y){
	p2[tot2].id=y;
	p2[tot2].nxt=h2[x];
	h2[x]=tot2++;
}
void dfs(int x,int d){
	if(d==1){
		u1[x]=1;
		for(int i=h1[x];i!=-1;i=p1[i].nxt){
			if(!u2[p1[i].id]) dfs(p1[i].id,2);
		}
	}
	else if(d==2){
		u2[x]=1;
		for(int i=h2[x];i!=-1;i=p2[i].nxt){
			if(!u1[p2[i].id]) dfs(p2[i].id,1);
		}
	}
}
inline int pw(rint x,rint p){
	rint ret=1;
	while(p>0){
		if(p&1) ret=1ll*ret*x%mod;
		x=1ll*x*x%mod,p>>=1;
	}
	return ret;
}
int main(){
	freopen("partition.in","r",stdin);
	freopen("partition.out","w",stdout);
	prework();
	int T;cin>>T;
	while(T--){
		cin>>n;
		for(rint i=1;i<=n;i++)
			read(a[i]);
		memset(h1,-1,sizeof(h1));
		memset(h2,-1,sizeof(h2));
		memset(u1,0,sizeof(u1));
		memset(u2,0,sizeof(u2));
		tot1=tot2=0;
		for(rint i=1;i<=n;i++){//nlogn
			int x=a[i];
			while(x>1){
				int d=fac[x];
				add_p1(d,i);
				add_p2(i,d);
				while(fac[x]==d){
					x/=prime[d];
				}
			}
		}
		int ans=0;
		for(rint i=1;i<=n;i++){
			if(!u2[i]){
				ans++;
				dfs(i,2);
			}
		}
		cout<<(pw(2,ans)-2+mod)%mod<<endl;
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章