CF1778F Maximizing Root - 树形 dp -
题目链接:https://codeforces.com/problemset/problem/1778/F
题解:
设 表示考虑到 结点,要让子树内的点都变成 第 小约数的倍数的话,至少要操作多少次
首先预处理一下 的所有约数
考虑 每一次加一个子树 时的转移:
其中 就是要考虑是否能通过操作 这个点使得 及子树的点能满足是 的倍数
如果 ,那么
否则,如果,则
否则,
最后答案就是
代码:
// by SkyRainWind
#include <bits/stdc++.h>
#define mpr make_pair
#define debug() cerr<<"Yoshino\n"
#define pii pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef long long LL;
const int inf = 1e9, INF = 0x3f3f3f3f, maxn = 2e5+5;
int n,k;
int a[maxn];
vector<int>g[maxn], divs[1005];
vector<int>dp[maxn];
void dfs(int x,int fat=0){
dp[x].clear();
dp[x].resize(divs[a[x]].size());
for(int u : g[x])if(u != fat){
dfs(u, x);
for(int j=0;j<divs[a[x]].size();j++){
int dj = divs[a[x]][j], r = k+1;
for(int kk=0;kk<divs[a[u]].size();kk++){
int dk = divs[a[u]][kk];
if(dk%dj == 0){
r = min(r, dp[u][kk]);
}else if(dk*dk%dj == 0){
r = min(r, dp[u][kk] + 1);
}
}
dp[x][j] = min(dp[x][j] + r, k+1);
}
}
dp[x][0] = 0;
}
void solve(){
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&a[i]), g[i].clear();
for(int i=1;i<n;i++){
int x,y;scanf("%d%d",&x,&y);
g[x].pb(y), g[y].pb(x);
}
dfs(1);
for(int i=dp[1].size()-1;i>=0;i--)
if(dp[1][i] < k){
printf("%lld\n",1ll*a[1]*divs[a[1]][i]);
return ;
}
printf("%d\n",a[1]);
}
signed main(){
for(int i=1;i<=1000;i++)
for(int j=i;j<=1000;j+=i)
divs[j].pb(i);
int an=0;
for(int i=1;i<=1000;i++)an=max(an,(int)divs[i].size());
cout << an;
int te;scanf("%d",&te);
while(te --)solve();
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示