CF1778F Maximizing Root - 树形 dp -

题目链接:https://codeforces.com/problemset/problem/1778/F

题解:
dpi,j 表示考虑到 i 结点,要让子树内的点都变成 aij 小约数的倍数的话,至少要操作多少次
首先预处理一下 1..1000 的所有约数
考虑 x 每一次加一个子树 u 时的转移:
dp[x][i]+=dp[u][j]+w(divs[a[x]][i],divs[a[u]][j])
其中 w 就是要考虑是否能通过操作 u 这个点使得 u 及子树的点能满足是 divs[a[x]][i] 的倍数
如果 divs[a[x]][i]|divs[a[u]][j] ,那么 w=0
否则,如果divs[a[x]][i]|divs[a[u]][j]2,则 w=1
否则,w=

最后答案就是 a[1]×divs[a[1]][i],if dp[1][i]<k

代码:

// 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;
}
posted @   SkyRainWind  阅读(31)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示
点击右上角即可分享
微信分享提示