hdu 4701 Game

比赛时没做出来,表示被当时的198交9A给惊呆了。。。。。。

赛后才有了想法。

思路:Alice和Bob得金币总和为all,然后找到第一个前缀和大于all的数,这个位置是不可能到达的点。

           eg:alice有10金币,bob有10金币,则all=20金币,共有5个商品5,6,7,8,9。这样的话第四个点8是不可能到达的,因为到那里需要26金币。

           所以找到这个点之后我们要从他前面这个点开始往前递推,可以通过dp,dp[i]就表示到达i这个点时必胜需要多少个金币

           还是这个样例eg:alice有10金币,bob有10金币,则all=20金币,共有5个商品5,6,7,8,9。

           从第三个位置开始,显然dp[3]=7,因为只要能买得起这个商品,就是必胜,第四个点时无法到达的。

           对于第二个位置,要获得必胜,有两种决策:   

                                                  决策1:直接到达后继的必胜态。即dp[2]=6+dp[3]=13;

                                                  决策2:留给对手一个必败态,即对手下一次最多只能有(dp[3]-1)=6个金币,当前有all-5=15个金币,则dp[2]=15-6=9;

                                                  两者取较小值,即dp[2]=9;

          对于第一个位置,同样的,有两种决策:

                                                  决策1:直接到达后继的必胜态。即dp[1]=5+dp[2]=14;

                                                  决策2:留给对手一个必败态,即对手下一次最多只能有(dp[2]-1)=8个金币,当前有all=20个金币,则dp[1]=20-8=12;

                                                 取较小值,dp[1]=12;

         得到了dp[1]后,只需要比较dp[1]和Alice的金币大小即可,alice的金币>=dp[1]时,alice必胜,否则必败。ect:这里10<dp[1],所以alice必败。

                        

#include<stdio.h>
unsigned int all,sum[1111111],s[1111111],dp[1111111];
int main()
{
    int i,n;
    int x,y;
    while(scanf("%d%d%d",&n,&x,&y)!=-1)
    {
        all=x+y;
        int len=n,flag=0;
        for(i=1;i<=n;i++)scanf("%u",&s[i]);
        for(i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+s[i];
            if(sum[i]>all){
                len=i-1;
                break;
            }
        }
        dp[len]=s[len];
        unsigned int tmp;
        for(i=len-1;i>0;i--)
        {
            tmp=all-sum[i-1];
            dp[i]=tmp-dp[i+1]+1;
            tmp=dp[i+1]+s[i];
            if(tmp<dp[i])dp[i]=tmp;
        }
        if(x>=dp[1])puts("ALICE");
        else        puts("BOB");
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值