传送门
//题意 : 中文的还是不要偷懒, 自己读吧.
//思路 : 利用完全背包. dp[i][j]代表打死防御力为i, 生命值为j的怪兽最少需要消耗的晶体数. 由于技能可以被无限多次使用, 那么这就有点类似完全背包了, 每一种物品可以放无限多次. 所以就是一道裸题了, 直接上就是了, 注意维护的一个最小, 即可以打倒高血量的晶体数那么也一定可以打倒低血量的, 所以需要更新一个最小值. 因为我们并不是一一去减的, 而是跳着减的, 所以有可能最优的被减掉了. 所以需要再次维护一下.
AC Code
/** @Cain*/
const int maxn = 1e3+10;
int n,m;
ll dp[15][maxn], k[maxn], p[maxn], a[maxn*100], b[maxn*100];
void solve()
{
while(~scanf("%d%d",&n,&m)){
for(int i=1;i<=n;i++)
scanf("%I64d%I64d",&a[i],&b[i]);
for(int i=1;i<=m;i++)
scanf("%I64d%I64d",&k[i],&p[i]);
for(int i=0;i<=10;i++){
for(int j=0;j<maxn*2;j++){
dp[i][j] = INF;
}
}
for(int i=0;i<=10;i++){
dp[i][0] = 0; //初始化.
for(int j=0;j<=maxn;j++){
for(int h=1;h<=m;h++){
ll tmp = p[h] - i;
if( tmp < 0 || j - tmp < 0) continue;
dp[i][j] = min(dp[i][j],dp[i][j-tmp]+k[h]);
}
}
for(int j=maxn;j>=0;j--)
dp[i][j] = min(dp[i][j],dp[i][j+1]);
}
ll res = 0;
for(int i=1;i<=n;i++) res += dp[b[i]][a[i]];
if(res > INF) printf("-1\n");
else printf("%I64d\n",res);
}
}