题意:
将一个长度为
n
n
n的序列,划分为
S
、
T
S、T
S、T两个集合,要求
g
c
d
(
∏
i
ϵ
S
a
i
,
∏
j
ϵ
T
a
j
)
=
=
1
gcd(\prod_{i\epsilon S}a_i,\prod_{j\epsilon T}a_j)==1
gcd(∏iϵSai,∏jϵTaj)==1
求一共有多少种不同的方案
分析:
为了保证两个集合内的元素都互质,我们先通过线性素筛求出每个数的最小质因子,然后通过这个将每对
a
i
a_i
ai和与
t
a
ta
ta有相同的质因子的其他的
a
j
a_j
aj建边
最后我们求一遍有多少个联通块(记为
s
s
s),而最后的答案就是
2
s
−
2
2^s-2
2s−2
代码:
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<queue>
#include<map>
#include<cmath>
#include<vector>
#define LL long long
#define mo 1000000007
using namespace std;
inline LL read() {
LL d=0,f=1;char s=getchar();
while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
while(s>='0'&&s<='9'){d=d*10+s-'0';s=getchar();}
return d*f;
}
int p[1000005],zp[1000005],tf[1000005],cntt=0;
void ss()
{
for(int i=2;i<=1000000;i++)
{
if(!tf[i]) p[++cntt]=i,zp[i]=i;
for(int j=1;j<=cntt&&i*p[j]<=1000000;j++)
{
tf[i*p[j]]=1;
zp[i*p[j]]=p[j];
if(!(i%p[j])) break;
}
}
return;
}
int g[1000005],tt[1000005];
struct node{
int to,next;
}e[2000005];
int ls[2000005],cnt;
void add(int x,int y)
{
e[cnt]=(node){y,ls[x]};
ls[x]=cnt++;
return;
}
void dfs(int fa,int u)
{
tt[u]=1;
for(int i=ls[u];~i;i=e[i].next)
{
int v=e[i].to;
if(v==fa||tt[v]) continue;
dfs(u,v);
}
return;
}
int main()
{
int size = 256 << 20; //250M
char*p=(char*)malloc(size) + size;
__asm__("movl %0, %%esp\n" :: "r"(p) );
ss();
int t=read();
while(t--)
{
memset(g,0,sizeof(g));memset(tt,0,sizeof(tt));
memset(ls,-1,sizeof(ls));cnt=0;
int n=read();
for(int i=1;i<=n;i++)
{
int a=read();
if(!tf[a]) {if(g[a]&&a!=1) add(i,g[a]),add(g[a],i);g[a]=i;continue;}
while(a>1)
{
if(g[zp[a]]) add(i,g[zp[a]]),add(g[zp[a]],i);
g[zp[a]]=i;
int bc=a;
while(!(a%zp[bc])) a/=zp[bc];
}
}
int ans=1;
for(int i=1;i<=n;i++)
{
if(tt[i]) continue;
(ans*=2)%=mo;
dfs(0,i);
}
printf("%d\n",(ans+mo-2)%mo);
}
return 0;
}