[CF1553G] Common Divisor Graph

\(\text{Problem}:\)Common Divisor Graph

\(\text{Solution}:\)

第一步就把我这种🤡吊打了。

首先考虑答案上界为 \(2\),这是因为 \(2\mid \gcd(a_{s}(a_{s}+1),a_{t}(a_{t}+1))\)。确定上界后,可以枚举可能的答案。

若答案为 \(0\),则 \(s\)\(t\) 初始在一个连通块中,这很好维护。

若答案为 \(1\),这说明存在一个点 \(x\)\(a_{x}(a_{x}+1)\) 这个点可以将 \(s\)\(t\) 所在的连通块合并。

否则答案为 \(2\)

那么对每个点 \(x\) 求出 \(a_{x}+1\) 会使哪些连通块合并即可。由于 \(a_{i}\leq 10^{6}\),每个数质因子个数不超过 \(7\),故复杂度正确。

\(\text{Code}:\)

#include <bits/stdc++.h>
#pragma GCC optimize(3)
//#define int long long
#define ri register
#define mk make_pair
#define fi first
#define se second
#define pb push_back
#define eb emplace_back
#define is insert
#define es erase
#define vi vector<int>
#define vpi vector<pair<int,int>>
using namespace std; const int N=300010, M=1000010; 
inline int read()
{
	int s=0, w=1; ri char ch=getchar();
	while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); }
	while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar();
	return s*w;
}
int pri[M/5],cnt; bool book[M+5];
int n,T,a[N]; int vis[M+5]; vi g[M+5];
int f[N]; set<pair<int,int> > ne;
inline int Find(int x) { return f[x]^x?f[x]=Find(f[x]):x; }
inline void Merge(int x,int y)
{
	x=Find(x), y=Find(y);
	if(x^y) f[x]=y;
}
inline void Init()
{
	for(ri int i=2;i<=M;i++)
	{
		if(!book[i]) pri[++cnt]=i;
		for(ri int j=1;j<=cnt&&i*pri[j]<=M;j++)
		{
			book[i*pri[j]]=true;
			if(i%pri[j]==0) break;
		}
	}
}
signed main()
{
	n=read(), T=read();
	for(ri int i=1;i<=n;i++) a[i]=read(), f[i]=i;
	Init();
	for(ri int i=1;i<=n;i++)
	{
		int x=a[i];
		for(ri int j=1;pri[j]*pri[j]<=x;j++)
		{
			if(x%pri[j]) continue;
			g[pri[j]].eb(i);
			while(x%pri[j]==0) x/=pri[j];
		}
		if(x>1) g[x].eb(i);
	}
	for(ri int i=1;i<=M;i++)
	{
		if(book[i]) continue;
		int lst=-1;
		for(auto j:g[i])
		{
			if(~lst) Merge(lst,j);
			lst=j;
		}
	}
	for(ri int i=1;i<=n;i++)
	{
		int x=a[i];
		for(ri int j=1;pri[j]*pri[j]<=x;j++)
		{
			if(x%pri[j]) continue;
			vis[pri[j]]=Find(i);
			while(x%pri[j]==0) x/=pri[j];
		}
		if(x>1) vis[x]=Find(i);
	}
	for(ri int i=1;i<=n;i++)
	{
		int x=a[i]+1;
		vi q;
		for(ri int j=1;pri[j]*pri[j]<=x;j++)
		{
			if(x%pri[j]) continue;
			q.eb(pri[j]);
			while(x%pri[j]==0) x/=pri[j];
		}
		if(x>1) q.eb(x);
		for(auto &j:q) j=vis[j];
		for(ri int j=0;j<(int)q.size();j++)
		for(ri int k=j+1;k<(int)q.size();k++)
		if(q[j]&&q[k]) ne.is(mk(q[j],q[k]));
		for(auto j:q) if(j) ne.is(mk(j,Find(i)));
	}
	for(ri int i=1;i<=T;i++)
	{
		int s,t;
		s=read(), t=read();
		int fs=Find(s), ft=Find(t);
		int res;
		if(fs==ft) res=0;
		else if(ne.find(mk(fs,ft))!=ne.end()||ne.find(mk(ft,fs))!=ne.end()) res=1;
		else res=2;
		printf("%d\n",res);
	}
	return 0;
}
posted @ 2021-10-11 17:39  zkdxl  阅读(50)  评论(1编辑  收藏  举报