[题解]CF1101D GCD Counting

话说这是一道简单题

题意

给出一棵\(n\)个节点的树,每个节点上有点权\(a_i\)

求最长的树上路径,满足条件:路径上经过节点(包括两个端点)点权的\(gcd\)和不等于\(1\)

题解

首先看到题目,想到\(DP\)(怎么\(D\)?)

首先我们要想通一件事:\(gcd\)和不等于一就相当于该链不互质,所以只有在两点有相同质数时转移。所以这就很简单了,我们会想起二叉苹果树所以我们可以按质数分类,相当于处理质数个数次二叉苹果树。

由此,我们想到状态转移方程:

f[u][i]=max(f[u][i],f[v][k]+1)

然后这题就没了。

(码风巨丑,勿喷)

#include<bits/stdc++.h>
#define ll long long
#define N 220000
using namespace std;
ll n,fl,x,y,tot,ans,head[N],a[N],fg[N],TO[2*N],NXT[2*N],p[N][8],f[N][8];
ll pr[100]={0,2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293,307,311,313,317,331,337,347,349,353,359,367,373,379,383,389,397,401,409,419,421,431,433,439,443};
void add(ll f,ll to){
	TO[++tot]=to;
	NXT[tot]=head[f];
	head[f]=tot;
}
void dfs(ll u,ll fa){
	for(ll i=head[u];i;i=NXT[i]){
		ll v=TO[i];
		if(v==fa)continue;
		dfs(v,u);
		for(ll j=1;j<=fg[u];++j)
			for(ll k=1;k<=fg[v];++k)
				if(p[u][j]==p[v][k])
					ans=max(ans,f[u][j]+f[v][k]),f[u][j]=max(f[u][j],f[v][k]+1);
	}
}
int main(){
	scanf("%lld",&n);
	for(ll i=1;i<=n;++i)scanf("%lld",&a[i]),fl|=(a[i]-1);
	if(!fl){puts("0");return 0;}
	for(ll i=1;i<n;++i){
		scanf("%lld%lld",&x,&y);
		add(x,y);
		add(y,x);
	}
	for(ll i=1;i<=n;++i)
		for(ll j=1;j<=86;++j)
			if(a[i]%pr[j]==0)
				p[i][++fg[i]]=pr[j],f[i][fg[i]]=1;
	dfs(1,1);
	if(ans)printf("%lld",ans);
	else puts("1");
}

大家可能会看到我的代码里有很多卡常的东西,请不要见怪 (不都是因为毒瘤数据吗。。。)

posted @ 2020-04-27 09:11  ZTC_ZTC  阅读(106)  评论(0编辑  收藏  举报