BZOJ5046: 分糖果游戏

138 篇文章 0 订阅

%%%Claris

这道题的能量只是用来让过当前回合的,而一个人让了,另一个人也可以让回来,两人具体的能量是多少不重要,重要的是A和B能量的差值,如果差值>0,A才可以让过这一回合

用能量值DP的方程很好想,但是能量值太大了没有用
因为糖果的美味度不大,考虑用这个东西DP
令f[i][j]表示当前先手能够在第i~n个糖果拿到至少j的美味度,先后手能量的差最少可以是多少
s[i]表示i~n的糖果美味度之和
对于第i个糖果,假如当前先手是A,后手是B
如果A选择取这个糖果,因为他至少要拿到j的美味度,所以到后手时后手不能在i+1~n拿到s[i]-j+1的美味度,即对于后手来说 BA>=f[i+1][s[i]j+1] 不成立
所以有 f[i][j]=(f[i+1][s[i]j+1]1)r[i]
如果A选择让,首先A-B>=1,然后要保证让了之后,(A-1-(B+r[i]) 至少拿到j的美味度
f[i][j]=max(1,f[i+1][j]+r[i]+1)

转移的时候很多是否合法没判挂了很多发…

code:

#include<set>
#include<map>
#include<deque>
#include<queue>
#include<stack>
#include<cmath>
#include<ctime>
#include<bitset>
#include<string>
#include<vector>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<complex>
#include<iostream>
#include<algorithm>
#define ll long long
#define inf 1e14
using namespace std;

const int maxn = 210;
const int maxv = 210;

int n,m,A,B;
ll r[maxn];
int s[maxn],v[maxn];
ll f[maxn][maxv];

int main()
{
    scanf("%d%d%d",&n,&A,&B);
    for(int i=1;i<=n;i++)
    {
        int x,y; scanf("%d%d",&y,&x);
        v[i]=x; r[i]=y;
    }
    for(int i=n;i>=1;i--) s[i]=s[i+1]+v[i];

    for(int i=0;i<=v[n];i++) f[n][i]=-inf;
    for(int i=v[n]+1;i<=s[1];i++) f[n][i]=inf;

    for(int i=n-1;i>=1;i--) for(int j=0;j<=s[i];j++)
    {
        if(v[i]>=j) f[i][j]=-inf;
        else f[i][j]=-(f[i+1][s[i]-j+1]-1)-r[i];
        ll tmp=max(1ll,f[i+1][j]+r[i]+1);
        if(j<=s[i+1]&&f[i][j]>tmp) f[i][j]=tmp;
    }
    int ansi;
    for(int i=0;i<=s[1]&&(ll)A-B>=f[1][i];i++) ansi=i;
    printf("%d %d\n",ansi,s[1]-ansi);

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值