QOJ.ac

QOJ

Type: Editorial

Status: Open

Posted by: jiangly

Posted at: 2026-04-15 16:04:05

Last updated: 2026-04-17 09:25:19

Back to Problem

题解

设两个数为 $gx$ 和 $gy$,其中 $\gcd(x,y)=1$,则有边的条件相当于 $g(xy-A)=B$。容易发现这样的边数并不多,我们可以枚举 $g$,再枚举 $x$ 得到 $y$,总的边数不会超过 $D^2$,其中 $D$ 为 $A+B$ 范围内的约数个数最大值,大约在 $10^3$ 级别。实际上这是一个比较松的上界,很难取满。

找到所有边之后 BFS 预处理即可回答询问。注意这个图只有 $10^{16}$ 个点,而我们找到的数对可能超过这个范围。

Comments

avatar
HFDYW
#include <bits/stdc++.h> #define int long long using namespace std; inline int Read() {int x=0,f=1;char ch=getchar();while(ch<48||ch>57) {if(ch==45)f=-1;ch=getchar();}while(ch>=48&&ch<=57) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();return x*f;} inline void Write(int x,char ed='\n'){if(!x){putchar('0'),putchar(ed);return;}if(x<0)putchar('-'),x=-x;char a[20];int i=0;while(x)a[++i]=x%10+48,x/=10;for(;i;i--)putchar(a[i]);putchar(ed);} const int kN=5e5+10,kM=1e5+10,kMod=998244353; void Work(); int Find(int x); void Check(int x); void Merge(int x,int y); map<int,pair<int,int>>fa; vector<int>fac; signed main() { // ios::sync_with_stdio(false); // cin.tie(0),cout.tie(0); // freopen("in.in","r",stdin); // freopen("out.out","w",stdout); int T=1; while(T--)Work(); return 0; } void Work() { int a=Read(),b=Read(); for(int i=1;i*i<=b;i++) if(b%i==0)fac.push_back(i),(i*i==b? 0:(fac.push_back(b/i),1)); for(int num:fac) { int temp=b/num+a; for(int i=1;i*i<=temp;i++) if(temp%i==0&&__gcd(i,temp/i)==1) Merge(i*num,temp/i*num); } int q=Read(); while(q--) { int x=Read(); if(!fa.count(x))Write(x); else Write(fa[Find(x)].second); } } void Check(int x) { if(fa.count(x))return; fa[x]={x,x}; } void Merge(int x,int y) { if(max(x,y)>1e16)return; Check(x),Check(y); int fax=Find(x),fay=Find(y); if(fax!=fay)fa[fax].first=fay,fa[fay].second^=fa[fax].second; } int Find(int x) { return fa[x].first==x? x:fa[x].first=Find(fa[x].first); }