[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;
}
夜畔流离回,暗叹永无殿。
独隐万花翠,空寂亦难迁。
千秋孰能为,明灭常久见。
但得心未碎,踏遍九重天。