zoukankan      html  css  js  c++  java
  • 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)
  • 相关阅读:
    Leetcode 50.Pow(x,n) By Python
    Leetcode 347.前K个高频元素 By Python
    Leetcode 414.Fizz Buzz By Python
    Leetcode 237.删除链表中的节点 By Python
    Leetcode 20.有效的括号 By Python
    Leetcode 70.爬楼梯 By Python
    Leetcode 190.颠倒二进制位 By Python
    团体程序设计天梯赛 L1-034. 点赞
    Wannafly挑战赛9 C-列一列
    TZOJ Start
  • 原文地址:https://www.cnblogs.com/lochan/p/3408150.html
Copyright © 2011-2022 走看看