hdu 4701 博弈难题

来源:互联网 发布:ubuntu默认字体是什么 编辑:程序博客网 时间:2024/06/10 10:35

思路:

▶ 设 win(i,x,y) 表示当前可以买的物品是 i,先手有 x 元,后 手有 y 元时,先手是否必胜

▶ win(i,x,y) ⇐⇒∃j((j > i)∧(x ≥ si−sj)∧¬win(j,y,x−si +sj))

▶ 其中 si = Ci + Ci+1 +···+ CN

▶ 注意到 x + y = A + B−s1 + si,即 win(i,x) := win(i,x,y)

▶ win(i,x) =⇒ win(i,x + 1)

▶ 设 m(i) = min{x : win(i,x)},则 ¬win(i,x) ⇐⇒ x ≤ m(i)−1

▶ 令 D = A + B−s1 + si

▶           m(i) =min{x : ∃j((j > i)∧(x ≥ si −sj)∧¬win(j,D−x))}

          =min{x : ∃j((j > i)∧(x ≥ si −sj)∧D−x ≤ m(j)−1}

          =min{max{si −sj,D−m(j) + 1} : j > i}

          =min{max{si −sj,A + B−s1 + si −m(j) + +1} : j > i}

          =si + min{max{−sj,A + B−s1 −m(j) + 1} : j > i}

▶ 只要测试 A ≥ m(1)

#include <iostream>#include <cstdio>#include <vector>#include <cmath>#include <cstring>using namespace std;long long s[1000500];int main (){    int n,a,b;    while(scanf("%d%d%d",&n,&a,&b)!=EOF)    {        for(int i=1;i<=n;++i)            scanf("%I64d",&s[i]);        for(int i=n-1;i>=1;--i)            s[i]+=s[i+1];        long long pre_min=0,now_min;        for(int i=n;i>=1;--i)        {            now_min=pre_min+s[i];            pre_min=min(pre_min,max(-s[i],a+b-s[1]+1-now_min));        }        if(a>=now_min)            printf("ALICE\n");        else printf("BOB\n");    }    return 0;}


原创粉丝点击