【题解】[Codeforces 815C] CF815C Karen and Supermarket【树形DP】
题意
\(n\) 个商品呈有根树结构。每个商品有价格 \(c_i\)。若其父亲使用了优惠券,自己可以使用优惠券。给定 \(m\),问 \(m\) 元至多买多少个商品。\(n\leq 5000\),\(c_i,d_i,m\leq 10^9\)
题解
设 \(f[i,j,0 /1]\) 为考虑 \(i\) 号点的子树、买了 \(j\) 件商品,自己是否使用优惠券时的最小花费。
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int getint(){
int ans=0,f=1;
char c=getchar();
while(c<'0'||c>'9'){
if(c=='-')f=-1;
c=getchar();
}
while(c>='0'&&c<='9'){
ans=ans*10+c-'0';
c=getchar();
}
return ans*f;
}
const int N=5e3+10,mod=998244353,inv2=(mod+1)/2;
struct bian{
int e,n;
};
bian b[N<<1];
int s[N],tot=0;
void add(int x,int y){
tot++;
b[tot].e=y;
b[tot].n=s[x];
s[x]=tot;
}
ll f[N][N][2],g[N][2];
int sz[N],c[N],d[N];
void ss(int x){
f[x][0][0]=0;
f[x][1][0]=c[x];
f[x][1][1]=c[x]-d[x];
sz[x]=1;
for(int i=s[x];i;i=b[i].n){
int v=b[i].e;
ss(v);
memset(g,0x3f,sizeof(g));
for(int j=0;j<=sz[x];j++){
for(int k=0;k<=sz[v];k++){
g[j+k][0]=min({g[j+k][0],
f[x][j][0]+f[v][k][0]});
g[j+k][1]=min({g[j+k][1],
f[x][j][1]+f[v][k][1],
f[x][j][1]+f[v][k][0]});
}
}
sz[x]+=sz[v];
memcpy(f[x],g,sizeof(g));
}
// cerr<<">>>>>>> "<<x<<endl;
// for(int i=0;i<=sz[x];i++)cerr<<"|| "<<i<<" "<<f[x][i][0]<<" "<<f[x][i][1]<<endl;
}
int main(){
int n=getint(),b=getint();
for(int i=1;i<=n;i++){
c[i]=getint();
d[i]=getint();
if(i>=2)add(getint(),i);
}
memset(f,0x3f,sizeof(f));
ss(1);
int ans=0;
for(int i=1;i<=n;i++)if(f[1][i][0]<=b||f[1][i][1]<=b)ans=i;
cout<<ans;
}