题目传送门:
题意描述:给出一棵\(n\)个节点的树,每个节点上有点权\(a_i\)。求最长的树上路径,满足条件:路径上经过节点(包括两个端点)点权的\(\gcd\)和不等于\(1\)。
首先,我们先明白一件事情:题目要求我们的\(\gcd\)之和不等于\(1\),指的是我们并不关心\(\gcd\)的值是多少,只要它大于\(1\)即可。而\(\gcd\)不是\(1\),意味着一定有公共质因子。
接下来就好办了,我们可以用\(f[x][j]\)表示以\(x\)为根的子树往下走,公共质因子为\(j\)的最大值
又因为不同的质因子个数十分少,所以几乎可以看成一个常数,可以暴力处理每一个节点的信息。显然最优解一定会被处理到。
代码:
#include<bits/stdc++.h>
namespace Bu_Yao_Tian_Tian_Bi_Sai {
using namespace std;
#define LL long long
inline LL read() {
char c=getchar();
LL sum=0;
while(c<'0'||c>'9') {
c=getchar();
}
while(c>='0'&&c<='9') {
sum=(sum<<3)-'0'+(sum<<1)+c,c=getchar();
}
return sum;
}
inline void write(LL x) {
if(x>9) {
write(x/10);
}
putchar(x%10+'0');
}
const int d[4][2]= {
{1,0},{0,1},{-1,0},{0,-1}
},mod=1e9+7,N=1e6+5;
}
using namespace Bu_Yao_Tian_Tian_Bi_Sai;
struct edge {
int to,nxt;
} e[N<<1];
int head[N],cnt,ans=1;
inline void add(int u,int v) {
e[++cnt].to=v,e[cnt].nxt=head[u],head[u]=cnt;
}
vector<int> p[N],f[N];
//p[u]:对u分解质因数后的结果
//f[u][v]:u为根的子树,往下走,公共质因子为v的最长链
int max(int u,int v) {
return u<v?v:u;
}
void dfs(int u,int fa) {
for(int i=head[u]; i; i=e[i].nxt) {
int v=e[i].to;
if(v==fa) {
continue ;
}
dfs(v,u);
for(int j=0; j<p[u].size(); j++) {
for(int k=0; k<p[v].size(); 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);
}
}
}
}
}
void fen(int x,int tmp) {
for(int i=2; i*i<=x; i++) {
if(x%i==0) {
p[tmp].push_back(i),f[tmp].push_back(1);
while(x%i==0) {
x/=i;
}
}
}
if(x>1) {
p[tmp].push_back(x),f[tmp].push_back(1);
}
}
int main() {
int n=read();
bool flag=0;
for(int i=1,x; i<=n; i++) {
x=read();
if(x^1) {
flag=1;
}
fen(x,i);
}
if(!flag) {
write(0);
return 0;
}
for(int i=1,u,v; i<n; i++) {
u=read(),v=read(),add(u,v),add(v,u);
}
dfs(1,0);
write(ans);
return 0;
}
/*
_ __
(_)/ \
<'_, ____)~~~~~~~
^^ ^^
*/
完美撒花~