参考了hzwer学长的blog。
设P[x]表示物品带来的能量,L[x]、M[x]表示物品购买上限、单价(高级装备的L与M需要自己算)。
L[x] = min(L[x], m/M[x]) 贫穷限制了购买力。
f[i][j][k]表示在第i个物品为根的子树中,有j件x物品是用于上层的合成(那么这j件物品的能量值并不在此时体现),花费为k时带来的最大能量。
显然对于基本装备,有:
for(int i = 0; i <= L[x]; ++i)
for(int j = i; j <= L[x]; ++j)
f[x][i][j * M[x]] = (j - i) * P[x];
这可能是一个森林,所以对于每棵树,我们都进行dp。
在对高级装备x及其子树进行dp的时候,我们定义g[i][j]表示,对于x的前i个儿子(按邻接表的顺序定义的),花费为j,所能获得的最大能量。
假设我们要合成l个x物品,剩下的钱买一些x子树内的装备,并不用于合成。
g[tot][j] = max{g[tot - 1][j - k] + f[e[i].to][l*e[i].val][k]}
//e[i].to是x的第i个儿子,e[i].val是合成x所需的第i个子装备的数量。k表示从j中拿出k的钱买子树内装备,此时的tot还在逐渐累加,并不是一个定值
最后枚举这l个x装备中,有j个用于合成,其他用于直接增加能量
f[x][j][k] = max{g[tot][k] + P[x] * (l - j)} //tot此时就表示儿子数量了
dp完x这棵树之后,我们回到主程序。
h[i][j]表示森林中的前i棵树,花费j元得到的最大能量值。
那么h[i][j] = max{h[i - 1][j1] + f[x][0][j - j1]}
//把j给前i-1棵树与x这棵树分。因为x没有父节点了,所以没有x物品用于上层合成
#include <cstdio>
#include <cstring>
#include <algorithm>
#define inf 1000000000
using namespace std;
int n, m, P[55], M[55], L[55], tot = 0, ans;
int f[55][105][2005], g[55][2005], h[55][2005];
struct adj {int to, val, next;}e[20005]; int head[55], deg[55], cnt = 1;
inline int read() {
int x = 0; char c = getchar();
while(c < '0' || c > '9') c = getchar();
while(c >= '0' && c <= '9') {x = x * 10 + c - 48; c = getchar();}
return x;
}
inline void ins(int u, int v, int w) {e[++cnt].to = v; e[cnt].val = w; e[cnt].next = head[u]; head[u] = cnt; ++deg[v];}
inline void dp(int x) {
if(!head[x]) {
L[x] = min(L[x], m/M[x]);
for(int i = 0; i <= L[x]; ++i)
for(int j = i; j <= L[x]; ++j)
f[x][i][j * M[x]] = (j - i) * P[x];
return ;
}
L[x] = inf;
for(int i = head[x]; i; i = e[i].next) {
dp(e[i].to);
L[x] = min(L[x], L[e[i].to]/e[i].val);
M[x]+= e[i].val * M[e[i].to];
}
L[x] = min(L[x], m/M[x]);
memset(g, -0x3f3f3f3f, sizeof(g));
g[0][0] = 0;
for(int l = L[x]; l >= 0; --l) {
int tot = 0;
for(int i = head[x]; i; i = e[i].next) {
++tot;
for(int j = 0; j <= m; ++j)
for(int k = 0; k <= j; ++k)
g[tot][j] = max(g[tot][j], g[tot - 1][j - k] + f[e[i].to][l * e[i].val][k]);
}
for(int j = 0; j <= l; ++j)
for(int k = 0; k <= m; ++k)
f[x][j][k] = max(f[x][j][k], g[tot][k] + P[x] * (l - j));
}
}
int main() {
n = read(); m = read();
for(int i = 1; i <= n; ++i) {
P[i] = read();
char ch[10]; scanf("%s", ch);
if(ch[0] == 'A') {
int x = read();
while(x--) {
int v = read(), num = read();
ins(i, v, num);
}
}else M[i] = read(), L[i] = read();
}
memset(f, -0x3f3f3f3f, sizeof(f));
for(int x = 1; x <= n; ++x)
if(!deg[x]) {
dp(x); ++tot;
for(int i = 0; i <= m; ++i)
for(int j = 0; j <= i; ++j)
h[tot][i] = max(h[tot][i], h[tot - 1][j] + f[x][0][i - j]);
}
for(int i = 0; i <= m; ++i) ans = max(ans, h[tot][i]);
printf("%d", ans);
return 0;
}