把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

CF1553G Common Divisor Graph

题面传送门
当时好像以为巨大多难写所以扔了,然后发现好像很好写来着?
首先这个答案肯定小于等于2,因为如果有至少一个偶数,那么对那个奇数做一次就连到一起了。如果两个都是奇数那么最多对两个分别做一次就好了。
那么只要看答案是不是\(0\)\(1\),如果不是那么答案一定为\(2\)
答案是\(0\)很好算,只需要将原数质因数分解,将这个对应的质因数用并查集合并到一起。最后看看是不是在一个集合中即可。
如果是\(1\)那么枚举是哪个位置被操作了,容易发现最多只会有\(28\)个联通块中间建了边,用个map存一下之后查询即可。
否则为\(2\)
时间复杂度大概是\(O(28n\log n+q\log n)\)实际上远远跑不满。
code:

#include<bits/stdc++.h>
#define I inline
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define abs(x) ((x)>0?(x):-(x))
#define re register
#define RI re int
#define ll long long
#define db double
#define lb long db
#define N (150000+5)
#define M (1000000+5)
#define mod 1000000007
#define Mod (mod-1)
#define eps (1e-9)
#define U unsigned int
#define it iterator
#define Gc() getchar() 
#define Me(x,y) memset(x,y,sizeof(x))
#define Mc(x,y) memcpy(x,y,sizeof(x))
#define d(x,y) (n*(x-1)+(y))
#define R(n) (rand()*rand()%(n)+1)
#define Pc(x) putchar(x)
#define LB lower_bound
#define UB upper_bound
#define PB push_back
using namespace std;
int n,m,k,A[N+5],Fl[M+5],pr[M+5],B[45],Bh,x,ph,y,La[M+5],fa[M+5];vector<int> G[M+5];map<int,int> F[M+5];
I int GF(int x){return fa[x]^x?fa[x]=GF(fa[x]):x;}I int ME(int x,int y){fa[GF(x)]=GF(y);}
I void calc(int x){RI i,j;Bh=0;y=x;while(y^1) B[++Bh]=GF(La[y]),y/=La[y];y=x+1;while(y^1) B[++Bh]=GF(La[y]),y/=La[y];sort(B+1,B+Bh+1);Bh=unique(B+1,B+Bh+1)-B-1;for(i=1;i<=Bh;i++) for(j=i+1;j<=Bh;j++) F[GF(B[i])][GF(B[j])]=1; }
int main(){
	freopen("1.in","r",stdin);
	RI i,j;scanf("%d%d",&n,&m);for(i=2;i<=M;i++){
		!Fl[i]&&(pr[++ph]=i,La[i]=i,fa[i]=i);for(j=1;j<=ph&&i*pr[j]<=M;j++) {Fl[i*pr[j]]=1;La[i*pr[j]]=pr[j];if(i%pr[j]==0) break;}
	}for(i=1;i<=n;i++){scanf("%d",&A[i]);x=A[i];y=La[x];x/=y;while(x^1) ME(La[x],y),x/=La[x];}
	for(i=1;i<=n;i++) calc(A[i]);while(m--) scanf("%d%d",&x,&y),x=GF(La[A[x]]),y=GF(La[A[y]]),printf("%d\n",x^y?(2-(F[x].count(y)||F[y].count(x))):0);
}
posted @ 2022-03-10 15:10  275307894a  阅读(36)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end