# 新魔法药水
## 题目描述
商店里有 $N$ 种药水,每种药水都有一个售价和回收价。小 $S$ 攒了 $V$ 元钱,还会 $M$ 种魔法,可以把一些药水合成另一种药水。他一天可以使用 $K$ 次魔法,问他一天最多赚多少钱?
## 输入格式
第一行四个数N、M、V、K
接下来N行,每行两个数,表示药水的售价和回收价。
接下来M行,每行若干个数,第一个数表示魔法的成品,第二个数是原料的种数,接下来为各种原料的编号
## 输出格式
第一行四个数 $N,M,V,K$。
接下来 $N$ 行,每行两个数,表示药水的售价和回收价。
接下来 $M$ 行,每行若干个数,第一个数表示魔法的成品,第二个数是原料的种数,接下来为各种原料的编号。
## 样例 #1
### 样例输入 #1
```
4 2 6 3
1 0
1 0
5 3
20 15
3 2 1 2
4 3 1 2 3
```
### 样例输出 #1
```
12
```
## 提示
### 数据范围及约定
对于全部数据,$N \le 60$,$M \le 240$,$V \le 1000$,$k \le 30$。
#include<bits/stdc++.h>
using namespace std;
const int inf=(int)1e9;
int cost[300][300],dp[1020][300],ant[301][50];
int n,m,v,k;
int b[10001],s[10001];
struct node{
int from,len;
int to[101];
}E[250];
void checkmax(int &x,int y)
{
if(x<y) x=y;
}
void checkmin(int &x,int y)
{
if(x>y) x=y;
}
void init()
{
for(int i=1;i<=n;i++)
{
for(int j=0;j<=k;j++) cost[i][j]=b[i];
}
for(int j=1;j<=k;j++)
{
for(int i=1;i<=m;i++)
{
for(int t=1;t<=E[i].len;t++)
{
for(int r=0;r<=j-1;r++)
{
ant[t][r]=inf;
for(int p=0;p<=r;p++) checkmin(ant[t][r],ant[t-1][p]+cost[E[i].to[t]][r-p]);
}
}
checkmin(cost[E[i].from][j],ant[E[i].len][j-1]);
}
}
}
void solve()
{
memset(dp,0,sizeof(dp));
for(int i=0;i<=v;i++)
{
for(int j=0;j<=k;j++)
{
for(int t=1;t<=n;t++)//新加药水种类
{
for(int p=0;p<=k-j;p++)//新用魔法次数
{
if(i+cost[t][p]>v||j+p>k) continue;
checkmax(dp[i+cost[t][p]][j+p],dp[i][j]+s[t]);
}
}
}
}
int ans=0;
for(int i=0;i<=v;i++)
{
for(int j=0;j<=k;j++) checkmax(ans,dp[i][j]-i);
}
cout<<ans<<endl;
}
int main()
{
scanf("%d%d%d%d",&n,&m,&v,&k);
for(int i=1;i<=n;i++) scanf("%d%d",&b[i],&s[i]);
for(int i=1;i<=m;i++)
{
scanf("%d",&E[i].from);
scanf("%d",&E[i].len);
for(int j=1;j<=E[i].len;j++) scanf("%d",&E[i].to[j]);
}
init();
solve();
return 0;
}