题解
题目大意 给你一个n的节点的无向树 每个点都有一个值 问路径上所有节点的gcd>1的最长路径长度
考虑2e5内的数字公因数最多7个 2357111317>2e5 素数筛把2e5内所有数字质因子存在vector
使用树形dp 自底向上求解 d[i][j]表示使用节点i第j公因子到达叶子的最多顶点 p[i][j]表示使用节点i第j公因子经过i点的最多顶点
在DFS回溯后 遍历当前节点和其子节点的公因子 如果有相同则按照树形dp求树的直径方法进行转移 转移时先不加当前节点
最后所有儿子节点编译结束再给每个公因子的d和p加上当前节点并更新答案
思路参考至紫名dalao博客
AC代码
#include <stdio.h>
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int MAXN = 2e5 + 10;
int a[MAXN], ans = 0;
int d[MAXN][10], p[MAXN][10]; //d[i]使用第j公因子到达叶子的最多顶点 p[i]使用第j公因子经过i的最多顶点
vector<int> pri[MAXN], e[MAXN];
void DFS(int x, int f)
{
for (int y : e[x]) if (y != f) //自底向上求解
{
DFS(y, x);
for (int i = 0; i < pri[a[x]].size(); i++)
for (int j = 0; j < pri[a[y]].size(); j++)
{
int px = pri[a[x]][i], py = pri[a[y]][j];
if (px == py) //具有相同公因子
{
p[x][i] = max(p[x][i], d[x][i] + d[y][j]); //选两个不相同的子节点
d[x][i] = max(d[x][i], d[y][j]); //先不计算自身
break;
}
}
}
for (int i = 0; i < pri[a[x]].size(); i++) //2e5最多7个质因子 2*3*5*7*11*13*17>2e5
p[x][i] += 1, d[x][i] += 1, ans = max(ans, p[x][i]); //自身1个
}
int main()
{
#ifdef LOCAL
freopen("C:/input.txt", "r", stdin);
#endif
for (int i = 2; i < MAXN; i++)
if (pri[i].size() == 0)
{
pri[i].push_back(i); //添加自身
for (int j = i + i; j < MAXN; j += i)
pri[j].push_back(i); //增加质因子
}
int n;
cin >> n;
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
for (int i = 1; i < n; i++)
{
int u, v;
scanf("%d%d", &u, &v);
e[u].push_back(v), e[v].push_back(u);
}
DFS(1, 0);
cout << ans << endl;
return 0;
}