【一句话题意】给定一个包含N 个非负整数的集合A,请将A 分成两个子集P、Q,且使得 g c d ( Π P i Π Q i ) = = 1 gcd(\Pi P_i \Pi Q_i)==1 gcd(ΠPiΠQi)==1。请计算这样的划分方法总数mod1000000007 后的值。 n<=1e6
【分析】一道可做的数论题。按质因数划分,P和Q中不能有相同的质因数,拥有相同质因数的数必须放在同一个集合。将每个数分解质因数后,将每个数和质因数之间连一个双向边,显然的是每个连通块都必须放在同一个集合。考虑方案时,从1到n-1枚举放入集合P的连通块的组合方案数就是
C
1
n
+
C
2
n
+
.
.
.
.
.
+
C
n
−
1
n
C^n_1+C^n_2+.....+C^n_{n-1}
C1n+C2n+.....+Cn−1n。
这里有个小技巧:
C
0
n
+
C
1
n
+
.
.
.
.
.
.
+
C
n
−
1
n
+
C
n
n
=
2
n
C^n_0+C^n_1+......+C^n_{n-1}+C^n_n=2^n
C0n+C1n+......+Cn−1n+Cnn=2n(每个数都有选或不选两种情况)
所以方案数就是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;
}