【題解】CF990G GCD Counting

CF990G GCD Counting

\(\text{Solution:}\)

考慮一個 naive 的想法,首先直接枚舉答案 \(i,\) 然後把所有是 \(i\) 的倍數的點全部拉出來,這樣它們就會組成一些連通塊。

依次統計其路徑條數,那麼這些就是 \(i|\gcd\) 的答案。

那麼設 \(f(i)\) 表示我們算出來的答案,設 \(F(i)\) 表示我們想要的答案。

那麼此時顯然有 \(f(i)=\sum_{i|d} F(d)\)

直接考慮一波反演,\(F(i)=\sum_{i|d}\mu(\frac{d}{i})f(d)\) 即可。

這裏有一些學習到的小技巧以及注意事項:

首先是如何把所有點拉出來形成連通塊:直接維護點的話發現再枚舉連接它的邊複雜度就炸了,所以考慮直接找邊。對於一條邊,求其端點的 \(\gcd,\) 然後暴力找其因數記錄編號即可。

連邊可以用並查集維護一下 \(siz\)

然後注意莫反的時候要用到所有是它倍數的點的答案,所以不要因爲這個點的實際答案是 \(0\) 就直接不去計算,這樣會導致反演出錯

還有,注意到 \(256M\) 的空間一定要留意,這題一旦 #define int long long 就直接炸空間了

#include<bits/stdc++.h>
using namespace std;
typedef double db;
//#define int long long
const int mod=1e9+7;
const db eps=1e-10;
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline db Max(db x,db y){return x-y>eps?x:y;}
inline db Min(db x,db y){return x-y<eps?x:y;}
inline int Add(int x,int y,int M=mod){return (x+y)%M;}
inline int Mul(int x,int y,int M=mod){return 1ll*x*y%M;}
inline int Dec(int x,int y,int M=mod){return (x-y+M)%M;}
typedef pair<int,int> pii;
#define fi first
#define se second
#define mk make_pair
#define pb emplace_back
#define poly vector<int>
#define Bt(a) bitset<a>
#define bc __builtin_popcount
#define pc putchar
#define ci const int&
inline int Abs(int x){return x<0?-x:x;}
//char buf[1<<21],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
//char Obuf[1<<21],*O=Obuf;//Siz shoule be the size of Out File
//int pst[30],ptop;
//inline void Fwrite(int x){
//	if(x<0)*O++='-',x=-x;ptop=0;
//	while(x)pst[++ptop]=x%10,x/=10;
//	while(ptop)*O++=pst[ptop--]+'0';
//}
//inline void Fprint(){fwrite(Obuf,1,O-Obuf,stdout);}
inline int read(){
	int s=0,w=1;
	char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
	while(isdigit(ch)){s=s*10+ch-'0';ch=getchar();}
	return s*w;
}
inline void write(int x){
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline int qpow(int x,int y){
	int res=1;
	while(y){
		if(y&1)res=Mul(res,x);
		x=Mul(x,x);y>>=1;
	}
	return res;
}
inline void cadd(int &x,int y){x+=y;}
inline void cmul(int &x,int y){x*=y;}
inline void cmax(int &x,int y){x=Max(x,y);}
inline void cmin(int &x,int y){x=Min(x,y);}
const int N=2e5+10;
namespace Refined_heart{
	int a[N],n,siz[N],vvis[N],pr[N],cntt,mu[N];
	long long g[N];
	struct E{int u,v;}edge[N];
	inline void pred(){
		mu[1]=1;
		for(int i=2;i<=200000;++i){
			if(!vvis[i])pr[++cntt]=i,mu[i]=-1;
			for(int j=1;j<=cntt&&pr[j]*i<=200000;++j){
				vvis[i*pr[j]]=1;
				if(i%pr[j]==0)break;
				mu[i*pr[j]]=-mu[i];
			}
		}
	}
	inline int gcd(int x,int y){return !y?x:gcd(y,x%y);}
	poly d[N];
	int node[N],rec[N],rcnt;
	int f[N],vis[N],V[N],ans[N];
	inline int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
	inline void merge(int x,int y){
		int fx=find(x);
		int fy=find(y);
		if(fx==fy)return;
		f[fx]=fy;siz[fy]+=siz[fx];
	}
	void solve(){
		n=read();
		for(int i=1;i<=n;++i)a[i]=read(),node[a[i]]++,siz[i]=1,f[i]=i;
		for(int i=1;i<n;++i){
			int u=read(),v=read();
			edge[i]=(E){u,v};
			int gd=gcd(a[u],a[v]);
			for(int j=1;j*j<=gd;++j){
				if(gd%j)continue;
				d[j].pb(i);
				if(j*j!=gd)d[gd/j].pb(i);
			}
		}
		pred();
		for(int i=200000;i;--i){
			int cnt=0;
			int ts=0;
			for(auto pos:d[i]){
				merge(edge[pos].u,edge[pos].v);
				++cnt;
				if(!vis[edge[pos].u]){
					rec[++rcnt]=edge[pos].u;
					vis[edge[pos].u]=1;
					++ts;
				}
				if(!vis[edge[pos].v]){
					rec[++rcnt]=edge[pos].v;
					vis[edge[pos].v]=1;
					++ts;
				}
			}
			long long ct=0;
			for(int now=i;now<=200000;now+=i)ct+=node[now];
			g[i]+=ct-ts;
			for(int j=1;j<=rcnt;++j){
				int v=rec[j];
				int fv=find(v);
				if(V[fv])continue;
				V[fv]=1;
				if(siz[fv]==1)++g[i];
				else{
					long long c=1ll*siz[fv]*siz[fv];
					c+=siz[fv];
					c/=2;
					g[i]+=c;
				}
			}
			for(int j=1;j<=rcnt;++j){
				int v=rec[j];
				vis[v]=0;
				int fv=find(v);
				V[fv]=0;
				siz[v]=1;
				f[v]=v;
			}
			rcnt=0;
		}
		for(int i=1;i<=200000;++i){
			long long aans=0;
			for(int k=1;i*k<=200000;++k)aans+=1ll*mu[k]*g[i*k];
			if(aans)printf("%d %lld\n",i,aans);
		}
	}
}
signed main(){
	freopen("in.txt","r",stdin);
	Refined_heart::solve();
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章