问题 A: x
时间限制: 1 Sec 内存限制: 256 MB
题面
题面谢绝公开。
题解
赛时想到了正解并且对拍了很久。对拍没挂,但是评测姬表示我w0了……一脸懵逼。
不难证明,如果对于两个数字$i,j$,$gcd_{i,j}>1$的话,那么这两个数字必定分在一组内,否则不满足条件。
因此考虑对每一个数字质因数分解。包含同一质因数的数字不能分在同一集合。
此时只需用并查集维护集合个数。最后统计集合分配即可。
注意:每一个1都可以单独分配在一个集合里使得答案满足条件。因此每一个1都应单独放在一个集合中。特判即可。
另外,直接质因数分解会T掉。事先筛一遍素数即可。(用了最慢的筛法,实测可过)
#include<bits/stdc++.h> #define int long long #define rint register int #define read(A) A=init() #define mod 1000000007 using namespace std; inline int init() { int a=0,b=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')b=-1;ch=getchar();} while(ch>='0'&&ch<='9'){a=(a<<3)+(a<<1)+ch-'0';ch=getchar();} return a*b; } int ToT,n,a[1000005],sum,prime[1000006],tot; int cnt,cp[1000003],pc[1000003],fa[1000003]; bool vis[1000005],isnt[1000005]; vector <int> v[1000003]; inline int get_fa(int x){return (fa[x]==x)?x:fa[x]=get_fa(fa[x]);} inline int gcd(int A,int B){return (B==0)?A:gcd(B,A%B);} inline void I_get() { for(rint i=2;i<=1000000;++i) { if(!isnt[i]) { prime[++tot]=i;int lin=2; while(lin*i<=1000000)isnt[lin*i]=1,lin++; } } } inline int qpow(int x,int y) { int num=1; while(y) { if(y&1)num=num*x%mod; x=x*x%mod;y>>=1; } return num; } inline void merge(int x,int y) { int fx=get_fa(x); int fy=get_fa(y); if(fx!=fy)sum--,fa[fy]=fx; return ; } inline void Devide(int id) { int x=a[id]; for(rint i=1;prime[i]<=sqrt(x);++i) { if(x%prime[i]==0) { x/=prime[i];while(x%prime[i]==0)x/=prime[i]; if(!vis[prime[i]]) { vis[prime[i]]=1;cp[++cnt]=prime[i];pc[prime[i]]=cnt; v[cnt].clear(); v[cnt].push_back(id); } else v[pc[prime[i]]].push_back(id); } } if(x>1) { if(!vis[x]) { vis[x]=1;cp[++cnt]=x;pc[x]=cnt; v[cnt].clear(); v[cnt].push_back(id); } else v[pc[x]].push_back(id); } return ; } signed main() { read(ToT);I_get(); while(ToT--) { read(n);sum=n; cnt=0; memset(vis,0,sizeof(vis)); for(rint i=1;i<=n;++i) { read(a[i]);fa[i]=i; if(a[i]!=1)Devide(i); } for(rint i=1;i<=cnt;++i) { int lin=v[i][0]; for(rint j=1;j<v[i].size();++j) merge(lin,v[i][j]); } printf("%lld ",(qpow(2,sum)-2+mod)%mod); continue; } }