【SSLOJ1480】X

题目

思路

显然任意两个 \(\gcd\) 不为 \(1\) 的数字必须分到一个组里。所以可以在筛质数的同时将有相同质因数的数字归到一个集合内,设最终有 \(m\) 个集合,那么答案为 \(2^m-2\)(减去两个空集合情况)。
我采用埃氏筛 + 并查集,时间复杂度 \(O(n\log \log n)\)。事实上暴力枚举质因数 + dfs 也是可以的。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

const int N=100010,M=1000010,MOD=1e9+7;
int Q,n,m,father[M];
bool vis[M],v[M];

void prework()
{
	for (int i=0;i<M;i++)
		father[i]=i,vis[i]=v[i]=0;
	m=0;
}

int find(int x)
{
	return x==father[x]?x:father[x]=find(father[x]);
}

ll fpow(ll x,int k)
{
	ll ans=1;
	for (;k;k>>=1,x=x*x%MOD)
		if (k&1) ans=ans*x%MOD;
	return ans;
}

int main()
{
//	freopen("data.txt","r",stdin);
	scanf("%d",&Q);
	while (Q--)
	{
		prework();
		scanf("%d",&n);
		for (int i=1,x;i<=n;i++)
		{
			scanf("%d",&x);
			vis[x]=1;
			if (x==1) m++;
		}
		for (int i=2,last;i<M;i++)
		{
			if (v[i]) continue;
			if (vis[i]) last=i;
				else last=0;
			for (int j=i*2;j<M;j+=i)
			{
				v[j]=1;
				if (vis[j])
				{
					if (last) father[find(j)]=find(last);
					last=j;
				}
			}
		}
		for (int i=2;i<M;i++)
			if (vis[i] && find(i)==i) m++;
		printf("%lld\n",(fpow(2LL,m)-2LL+MOD)%MOD);
	}
	return 0;
}
posted @ 2020-08-13 18:20  stoorz  阅读(92)  评论(0编辑  收藏  举报