E. GCD Counting - 树形DP
E. GCD Counting
https://codeforces.ml/group/MKpYqfAQQQ/contest/386626/problem/E
题意
给你一颗树 每个结点都有权值 求一条最长链 满足链上每个点的两个gcd都不等于1
思路
把每个结点的权值 分解质因子 dp从下往上转移
如果一个点的儿子结点与当前结点有相同的因子 父节点就可以从儿子结点转移过来
对与一个结点 答案可能是它两个质因子相同的最长子链相加 或者是一条唯一的链
\[dp[x][num] = max(dp[to][num] + 1, dp[x][num])
\]
dp[x][num]代表编号为x的点上的数质因子为num的最长链的长度
将dp[x][num]初始化为1
每次 更新答案 ans = max(ans, dp[x][num] + dp[to][num]) 注意这一行写在更新dp[x][num]之前
#include<bits/stdc++.h>
#include<iostream>
#include<vector>
#include<unordered_map>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-10;
const ll N = 2e5 + 5;
const int M = 1e6 + 5;
const ll mod = 1e9 + 7;
ll n, m;
ll a[N], vis[N], ans;
vector<ll>g[N], prime[N];
map<ll, ll>dp[N];
//分解每个数的质因子
void getprime(ll k) {
ll x = a[k];
for (int i = 2; i <= x / i; i++) {
if (!(x % i)) {
//a[i]大小可能会重复 vis记录 重复了就不再存因子操作
if (!vis[a[k]]) prime[a[k]].push_back(i);
//初始化为1
dp[k][i] = 1;
}
while (!(x % i)) x /= i;
}
if (x > 1) {
dp[k][x] = 1;
if (!vis[a[k]]) prime[a[k]].push_back(x);
}
vis[a[k]] = 1;
}
void dfs(ll x, ll fa) {
for (auto to : g[x]) {
if (to == fa) continue;
dfs(to, x);
for (auto num : prime[a[x]]) {
//两段长取最大 一定保证最长的那一条和另一条相加
ans = max(ans, dp[to][num] + 1 + dp[x][num] - 1);
//更新
dp[x][num] = max(dp[x][num], dp[to][num] + 1);
}
}
}
void solve() {
cin >> n;
ll f = 0;
for (int i = 1; i <= n; i++) {
cin >> a[i];
if (a[i] != 1) f = 1;
getprime(i);
}
if (!f) {
cout << 0 << '\n';
return;
}
ll x, y;
for (int i = 1; i < n; i++) {
cin >> x >> y;
g[x].push_back(y);
g[y].push_back(x);
}
ans = 1;
dfs(1, -1);
cout << ans << "\n";
}
signed main() {
IOS;
int t = 1;
//cin >> t;
while (t--) {
solve();
}
}

浙公网安备 33010602011771号