HDU 传送门
这是一道变形的完全背包。
我们用dp[i][j]表示打倒血量为i防御力为j的恶魔的最小花费。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
#define INF 0x3f3f3f3f
using namespace std;
LL n,m;
LL a[100009],b[100009];
LL k[1009],p[1009];
LL ans,dp[3001][20];//dp[i][j]表示打倒生命值为 i ,防御值为 j 的恶魔的最小花费
void work()
{
ans=0;
LL mp=0,mb=0,ma=0;//最大攻击值,最大防御值,最大生命值
for(int i=1;i<=n;i++) {scanf("%lld%lld",&a[i],&b[i]);mb=max(mb,b[i]);ma=max(ma,a[i]);}
for(int i=1;i<=m;i++) {scanf("%lld%lld",&k[i],&p[i]);mp=max(mp,p[i]);}
if(mp<=mb){printf("-1
");return;}
memset(dp,0,sizeof(dp));
for(int i=0;i<=mb;i++)//防御值
{
for(int j=1;j<=ma;j++)//生命值
{
dp[j][i]=INF;
for(int o=1;o<=m;o++)
{
LL down=p[o]-i;//伤害值
if(down<=0) continue;
else if(down>=j) dp[j][i]=min(dp[j][i],k[o]);//一次性打倒
else dp[j][i]=min(dp[j][i],dp[j-down][i]+k[o]);//打下一部分血量
}
}
}
for(int i=1;i<=n;i++)
ans+=dp[a[i]][b[i]];
printf("%lld
",ans);
}
int main()
{
while(scanf("%lld%lld",&n,&m)!=EOF) work();
return 0;
}