UVALive 5760 Alice and Bob

题意是黑板上有n个数\(S_i\)。每次操作可以把其中一个数减1或者将两个数合并为一个数。一个数变为0时,则不能再对其操作。

思路是发现最大的可操作次数为\( \sum S_i\)+(n - 1)。\( \sum S_i\)是把所有数消除需要的操作数。(n-1)表示我们最多可以合并(n-1)次。

同时我们发现,总操作数的奇偶决定了胜负。换言之,合并的次数决定论胜负。

当1个数为1时,假如我们将其消去,则合并的次数减1,总操作数的奇偶改变。

那么我们首先考虑,所有的数都>=2的情况,假如这种情况对应的最大的可操作次数为先手胜。那么因为所有数>=2,所以无论后手怎么操作,最多把某个数变为1。当后手把某个数变为1,先手将这个1与其他数合并,则不改变最大的可操作次数。

换言之,当每个数都>=2时,其最后的操作总数必然等于最大的可操作次数。也就是说,假如没有数是1,那么胜负则已经决定了。

所以我们对每个状态,只需要用1的个数和非1的数的个数,即可表示。

那么我们用one表示1的个数,m表示非1的数的总可操作数。

对于所有非1的数字,其变为1的情况只有m=1一种。

 

所以我们用dp(one,m)即可表示每个状态。然后扫其后续状态即可。具体的状态转移,看代码吧。

 

代码如下:

 1 #include"cstdio"
 2 #include"iostream"
 3 #include"cstring"
 4 #include"algorithm"
 5 #include"cstdlib"
 6 #include"vector"
 7 #include"set"
 8 #include"map"
 9 #include"cmath"
10 using namespace std;
11 typedef long long LL;
12 const LL MAXN=30;
13 
14 int f[60][60000];
15 int sg(int one,int m)
16 {
17     if(f[one][m]!=-1) return f[one][m];
18 
19     if(one==0) return f[one][m]=((m%2)==1);
20     if(m==1) return f[one][m]=sg(one+1,0);
21 
22     if(!sg(one-1,m)) return f[one][m]=1;        // one中移出1个
23 
24     if(m>0 && !sg(one,m-1)) return f[one][m]=1;    // m操作1次
25 
26     if(m>0 && !sg(one-1,m+1)) return f[one][m]=1;    // one中移动一个到m
27 
28     if(one>=2)                             // 两个one合并
29     {
30         if(m>0 && !sg(one-2,m+3)) return f[one][m]=1;
31         else if(m==0 && !sg(one-2,m+2)) return f[one][m]=1;
32     }
33 
34     return f[one][m]=0;
35 }
36 int main()
37 {
38 #ifdef LOCAL
39     freopen("in.txt","r",stdin);
40     // freopen("out.txt","w",stdout);
41 #endif
42     memset(f,-1,sizeof(f));
43     int t;
44     scanf("%d",&t);
45     for(int tt=1;tt<=t;tt++)
46     {
47         int n,one=0,m=0;
48         scanf("%d",&n);
49         for(int i=1;i<=n;i++)
50         {
51             int tmp;
52             scanf("%d",&tmp);
53             if(tmp==1) one++;
54             else m+=(tmp+1);
55         }
56         if(m) m--;
57         printf("Case #%d: ",tt);
58         if(sg(one,m)) printf("Alice\n");
59         else printf("Bob\n");
60     }
61     return 0;
62 }

 

posted @ 2017-04-16 17:22  HuaZhang  阅读(310)  评论(0编辑  收藏  举报