• HDU4701_Game


    很有意思,很好的一个题目。

    题目的意思是两个人初始状态分别有A和B元,现在有N件可买的商品。两人轮流买,商品必须从左到右买过去,一次可以买若干个。第一个无法买到商品的人输。

    一看就知道是博弈题目,但是这并不是什么模型式的博弈题目,其实是转化成递推来做的。

    一开始我也不知道到底应该怎么来考虑这个问题,于是就按照博弈的思想用Mex的思路去写这个题目,直到我T了发。

    后来在网上看到神牛们写的博客后才发现正确的解法。

    其实这个问题应该是这样来考虑的。

    首先告诉了你两个人初始的钱数,那么总共的钱数是确定。在买完若干件商品后,一部分的钱数已经花在了买商品上面(先不管是谁买的),另一部分的钱还分别留在两个人的手中。这样如果我们知道当前买完了某件商品后其中一个人的剩余的钱数,那么我们可以根据总钱数不变来推出另一个人手中的钱数。

    同时,如果在买某一件商品开始是,ALICE手中只要有x元就有了必胜的策略,那么他手中的钱数如果大于x,显然就也是必胜咯。

    有了这两点,我们可以来个递推,解决这个问题。

    状态f[i]表示在买第i件商品前,只要先手的人的钱数不少于f[i],那么他就有必胜的策略。

    什么意思呢?

    我们首先看看,A+B即总钱数,最多能买到多少件商品,显然后面的商品都是没有用的。

    然后,对于可买的最后的那件商品n,f[n]=a[n]; 因为根据总钱数,只要他能够买掉最后一件商品,下一个人一定无钱购买后面的商品。

    接下来就是从i递推到i-1了。

    首先从i-1到i可能有两种情况:

    一、第i-1个商品和第i个商品是同一个人购买,这说明要是在购买i-1个商品的时候就有必胜的策略,那么此时他手里的钱数必须不小于a[i-1]+f[i](买完第i-1个商品后,必须至少还剩下f[i]的钱)。

    二、第i-1个商品和第i个商品不是同一个人购买,这说明前一个人在购买了i-1个商品后,留下了一个必败态给下一个人去购买第i个商品,这里我们知道对于第i个商品,其必败态就是钱数不足f[i]。这样根据总价值的关系就可以推出这种情况下的f[i-1]了。

    综合上面的两种情况,我们知道f[i]就是两种情况中的最小值。

    这样逐一递推,到达求出f[1],显然我们只要把f[1]和A比较大小,就可以得出谁胜谁负了。

    题目很有意思,以前没做过这种类型的题目。赞一个。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #define maxn 1000100
     5 #define ll long long
     6 using namespace std;
     7 
     8 ll n,m,A,B,l,r,mid,tot;
     9 ll a[maxn],f[maxn],sum[maxn];
    10 
    11 ll find()
    12 {
    13     l=1,r=n;
    14     if (A+B>=sum[n]) return n;
    15     while (l<r)
    16     {
    17         mid=(l+r)>>1;
    18         if (sum[mid]>A+B) r=mid;
    19             else l=mid+1;
    20     }
    21     return l-1;
    22 }
    23 
    24 int main()
    25 {
    26     while (scanf("%I64d%I64d%I64d",&n,&A,&B)!=EOF)
    27     {
    28         sum[0]=0;
    29         tot=A+B;
    30         for (ll i=1; i<=n; i++) scanf("%I64d",&a[i]),sum[i]=sum[i-1]+a[i];
    31         if (A<sum[1])
    32         {
    33             printf("BOB
    ");
    34             continue;
    35         }
    36         if (A>=sum[n])
    37         {
    38             printf("ALICE
    ");
    39             continue;
    40         }
    41         n=find();  
    42         f[n]=a[n];
    43         if (tot-sum[n-1]-f[n]>=a[n]) f[n]=tot-sum[n-1]-a[n]+1;
    44         
    45         for (int i=n-1; i>=1; i--)
    46         {
    47             f[i]=a[i]+f[i+1];
    48             if (tot-sum[i-1]-f[i+1]+1<f[i]) f[i]=tot-sum[i-1]-f[i+1]+1;
    49         }
    50         
    51         if (f[1]>A) printf("BOB
    ");
    52             else printf("ALICE
    ");
    53     }
    54     return 0;
    55 }
    如有转载,请注明出处(http://www.cnblogs.com/lochan)
  • 相关阅读:
    团队项目冲刺第九天
    团队项目冲刺第八天
    团队项目冲刺第七天
    团队项目冲刺第六天
    vue-cli(vue脚手架)详细教程
    Ocelot+Consul 集群搭建实践
    docker部署net core项目
    nginx配置文件
    条码扫描器
    转载:MVVM模式解析和在WPF中的实现(六) 用依赖注入的方式配置ViewModel并注册消息
  • 原文地址:https://www.cnblogs.com/lochan/p/3408150.html
Copyright © 2020-2023  润新知