专栏文章
题解:P12444 [COTS 2025] 发好奖 / Hijerarhija
P12444题解参与者 3已保存评论 3
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 3 条
- 当前快照
- 1 份
- 快照标识符
- @minags5p
- 此快照首次捕获于
- 2025/12/01 23:13 3 个月前
- 此快照最后确认于
- 2025/12/01 23:13 3 个月前
首先,为了资本做局,员工 的奖金一定只有三种取值:。
然后可以直接当树形背包问题做,但你发现 数组的合并复杂度炸了。所以这个问题肯定不能直接当树形背包做。考虑换个思路。
注意本题的唯一特殊条件:如果 有正整数奖金,那么 也有正整数奖金,也就是 的所有祖先都得有奖金。
可以联想到(但是有点难联想到)dfs 序,因为对于节点 以及它的任意一个祖先 ,都满足 在 dfs 序上的位置严格小于 ;同时,一颗子树内的节点,在 dfs 序上也是连续的。
那么我们在 dfs 序上做这个背包问题,设 表示 dfs 序前 个员工总共拿 元奖金, 的最大值。转移也自然分为三种:
注意这里的第一个转移,从 直接转移到 是为了不给 子树内员工发放奖金。
时间复杂度 。
CPP#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fr first
#define sc second
#define pii pair<int,int>
#define yes cout<<"Yes\n"
#define no cout<<"No\n"
#define fo(i,l,r) for(int i=l;i<=r;i++)
#define ro(i,r,l) for(int i=r;i>=l;i--)
const int N=5005;
int n,m,a[N],b[N];
vector<int>e[N];
int dfn[N],tip,siz[N];
int dp[N][N];
void dfs(int u){
dfn[++tip]=u;
siz[u]=1;
for (auto v:e[u]){
dfs(v);
siz[u]+=siz[v];
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>n>>m;
fo(i,2,n){
int fa;
cin>>fa;
e[fa].push_back(i);
}
dfs(1);
fo(i,1,n)
cin>>a[i];
fo(i,1,n)
cin>>b[i];
memset(dp,-0x3f,sizeof dp);
dp[1][0]=0;
fo(i,1,n){
int x=dfn[i];
fo(j,0,m){
dp[i+siz[x]][j]=max(dp[i+siz[x]][j],dp[i][j]);
if (j<m)
dp[i+1][j+1]=max(dp[i+1][j+1],dp[i][j]);
if (j+b[x]<=m)
dp[i+1][j+b[x]]=max(dp[i+1][j+b[x]],dp[i][j]+a[x]);
}
}
int rs=0;
fo(i,0,m)
rs=max(rs,dp[n+1][i]);
cout<<rs<<'\n';
return 0;
}
相关推荐
评论
共 3 条评论,欢迎与作者交流。
正在加载评论...