蒟蒻不会做(话说DP是我死穴么,每逢DP必跪),于是膜拜了题解
f[i][j][k]
表示对于
i
及其子树花费
1、对于叶子节点
f[i][j][k∗price[i]]=(k−l)∗price[i]
2、对于非叶子节点
穷举总合成次数,
g[tot][k]
表示
i
的前
f[i][j][k]=maxg[tot][k]+(l−j)∗price[i]
g[tot][j]=maxg[tot][j−k]+f[a[i].v][l∗a[i].w][k]
code:
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int e,n,m;
struct hp{
int u,v,w;
}a[50001];
bool leaf[101],unroot[51];
int point[101],next[5001];
int f[101][101][2001];
int g[101][2001];
int power[101],limit[101],price[101];
void add(int u,int v,int w)
{e++; a[e].u=u; a[e].v=v; a[e].w=w; next[e]=point[u]; point[u]=e; unroot[v]=true;}
void treedp(int x)
{
int i,j,l,k,tot;
if (leaf[x])
{
limit[x]=min(limit[x],m/price[x]);
for (i=0;i<=limit[x];++i)
for (j=i;j<=limit[x];++j)
f[x][i][j*price[x]]=(j-i)*power[x];
}
else
{
limit[x]=0x7fffffff;
price[x]=0;
for (i=point[x];i;i=next[i])
{
treedp(a[i].v);
limit[x]=min(limit[x],limit[a[i].v]/a[i].w);
price[x]+=a[i].w*price[a[i].v];
}
limit[x]=min(limit[x],m/price[x]);
memset(g,-0x3f3f3f3f,sizeof(g));
g[0][0]=0;
for (l=limit[x];l>=0;--l)
{
tot=0;
for (i=point[x];i;i=next[i])
{
tot++;
for (j=0;j<=m;++j)
for (k=0;k<=j;++k)
g[tot][j]=max(g[tot][j],g[tot-1][j-k]+f[a[i].v][l*a[i].w][k]);
}
for (j=0;j<=l;++j)
for (k=0;k<=m;++k)
f[x][j][k]=max(f[x][j][k],g[tot][k]+(l-j)*power[x]);
}
}
}
int main()
{
int i,j,k,t,v,w,ans=0; char opt;
scanf("%d%d",&n,&m);
for (i=1;i<=n;++i)
{
scanf("%d",&power[i]);
scanf("%c",&opt);
while (opt!='A'&&opt!='B')
scanf("%c",&opt);
if (opt=='B')
{
leaf[i]=true;
scanf("%d%d",&price[i],&limit[i]);
}
if (opt=='A')
{
scanf("%d",&t);
while (t--)
{
scanf("%d%d",&v,&w);
add(i,v,w);
}
}
}
memset(f,-0x3f3f3f3f,sizeof(f));
for (i=1;i<=n;++i)
if (!unroot[i])
{
treedp(i);
for (j=0;j<=limit[i];++j)
for (k=0;k<=m;++k)
ans=max(ans,f[i][j][k]);
}
printf("%d\n",ans);
}