背景 Background
小Q玩开采金钱游戏因为赚了太多钱,而这些钱又没有用,所以他相当愤怒,投诉了出品游戏者。所以游戏出品者就推出了《购买气球》这一款游戏,这一游戏是可以使用经营餐厅游戏获得的钱的。
描述 Description
小Q在经营餐厅中赚下了Money元,这些钱可以用来从商店买红色或者蓝色的气球,打破一个红色气球可以让分数score变为原来的red倍,打破一个蓝色的气球可以让分数score加上blue,每当你的分值score到达一个值win[i](score>=win[i])可以获得额外奖励金钱gold[i]。 当然,开始小Q得到的分值为0。 注:任何操作或奖励前后都不能欠钱(money不能小于0)。
输入格式 Input Format
第一行八个正整数Money,N,S1,S2,cost1,cost2,red,blue。表示有N个奖励方案,商店有S1个红色气球,S2个蓝色气球,买一个红色气球要花费cost1元,买一个蓝色气球需要cost2元。Money,red,blue意思为题目所示。( 1 <= red <= 3 ,1 <= blue <= 10 ) 接下来N行,每行两个正整数win[i],gold[i],意义如题目所示。( 1 <= win[i] <= 10^8 , 1 <= gold[i] <= 10^6 )
输出格式 Output Format
一个数Max表示最多能得到的分数。(我们无视金钱)
DP,用f[i][j]表示买了i个红气球,j个蓝气球的最优分数,g[i][j]表示买了i个红气球,j个蓝气球的剩余钱数,将win升序排序last[i][j]表示在[i][j]状态已经使用了前last[i][j]次的奖励。边界 last[][]={1};g[0][0]=money;f[0][0]=0;状态转移方程 f[i][j]=max{f[i-1][j],f[i][j-1]} (0<=i<=s1,0<=j<=s2;i,j不同时等于0) g[i][j],last[i][j]随之更新。
#include<iostream>
#include<cstdlib>
using namespace std;
int money,n,s1,s2,cost1,cost2,red,blue,ans;
struct node
{
int win,gold;
}d[110];
int f[11][1010],g[11][1010],last[11][1010]={1};
int cmp(const void *a,const void *b)
{
return (*(node *)a).win-(*(node *)b).win;
}
int main()
{
int i,j,k;
cin>>money>>n>>s1>>s2>>cost1>>cost2>>red>>blue;
for (i=1;i<=n;i++) cin>>d[i].win>>d[i].gold;
qsort(d+1,n,sizeof(node),cmp);
g[0][0]=money;
for (i=0;i<=s1;i++)
for (j=0;j<=s2;j++)
{
if (i>=1)
if (g[i-1][j]>=cost1)
if (f[i][j]<f[i-1][j]*red)
{
f[i][j]=f[i-1][j]*red;
g[i][j]=g[i-1][j]-cost1;
if (f[i][j]>ans)ans=f[i][j];
for (k=last[i-1][j];k<=n;k++)
if (f[i][j]>=d[k].win) g[i][j]+=d[k].gold;else break;
last[i][j]=k;
}
if (j>=1)
if (g[i][j-1]>=cost2)
if (f[i][j]<f[i][j-1]+blue)
{
f[i][j]=f[i][j-1]+blue;
g[i][j]=g[i][j-1]-cost2;
if (f[i][j]>ans) ans=f[i][j];
for (k=last[i][j-1];k<=n;k++)
if (f[i][j]>=d[k].win) g[i][j]+=d[k].gold;else break;
last[i][j]=k;
}
}
cout<<ans<<endl;
return 0;
}