E. GCD Counting - 树形DP
E. GCD Counting
https://codeforces.ml/group/MKpYqfAQQQ/contest/386626/problem/E
题意
给你一颗树 每个结点都有权值 求一条最长链 满足链上每个点的两个gcd都不等于1
思路
把每个结点的权值 分解质因子 dp从下往上转移
如果一个点的儿子结点与当前结点有相同的因子 父节点就可以从儿子结点转移过来
对与一个结点 答案可能是它两个质因子相同的最长子链相加 或者是一条唯一的链
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();
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话