题意:
给定n堆石子,比如n=3,pile=(4,5,7),表示第1,2,3堆分别有石子4,5,7个。
Alice和Bob进行取石子游戏。
总是A先move。
每次move:
1.必须选中某堆:
2.在该堆中移除至少1个石子。(必选操作)
3.将该堆中的石子任意个数移到任何其他非空石子堆里去。(可选操作)
最当AB都有最优策略进行游戏时,最后胜者是谁。
思路:
1.
n=1时显然A肯定赢。
2.
n=2时状态(x,y);x<=y.
比如(1,1) ,此时A肯定输。
比如(1,2),此时A肯定赢,因为当A可以将(1,2)转换为(1,1)。(1,1)轮到B,B则死路一条。
比如(2,2), A输。
比如(2,3),A赢。
到这就发现蹊跷了吧?推广之:
比如(x,x),此时A肯定要输。因为无论A如果操作,将(x,x)转化为(x,y);y<x;B都会将(x,y)转化为(y,y)。不断下去最后A还是泪流满面地面临(1,1)的死路。
那(x,y)呢,显然此时A肯定要赢。因为(x,y)马上可以转化为(y,y),由上句可知,B就死定了。
3.
n=3.
(x,y,z);x<=y<=z;
显然当x=0时,即用n=2,(y,z)的思路来判断即可。
所以n=3时候x!=0;
而由n=2的思路可知,如果A将(x,y,z)转化为(0,y,y)后,B就输了。所以A的最佳策略是(x,y,z)转化为(0,y,y)
实际上是可以实现的:
取出z的y-x个石头(显然z>=y>y-x)(x!=0),然后将其放到x堆上,然后将z剩下的石头扔掉。
所以当n=3时,A赢。
4.
n=4时(x,y,z,k),显然A的最佳策略是取完之后还是n=4,因为如果n=3则B稳赢。
先考虑(x,x,y,y),(1,1,1,1)稳输,(1,1,2,2)稳输,所以先猜测(x,x,y,y)稳输。
因为(x,x,y,y)经过操作后,不会再是(i,i,j,j),不信可以(1,1,4,4)去试看看就知道为什么了。
而无论A对(x,x,y,y)进行任何操作变成(w,x,y,z),B都可以对(w,x,y,z)进行对称操作再转化为(w,w,x,x)。举例(1,1,5,5)=>(2,1,4,5) (2,1,4,5)=>(2,2,4,4)
这样一直下去A的下场还是1,1,2,2,或者1,1,1,1。还是稳输。
所以(x,x,y,y),A稳输。
而对于一般的(w,x,y,z)肯定可以转化为(i,i,j,j),不信举例几个试试就懂了。
所以面临一般的(w,x,y,z)时A稳赢了。
ok,到这其实就差不多了。就题论题,要勇敢地猜测勇敢地提交,否则再推倒下去不是时间不够就是反胃想吐了:
比如从n=1,2,3,4我们推测。
当n=奇数时A赢定了。
当n=偶数时,如可以分为n/2的两个一摸一样的堆。比如(x,x,y,y,z,z)=>(x,y,z)+(x,y,z)。
时A也死定了。
而其它情况A就赢定了。
#include<iostream> #include<algorithm> #define max(a,b) (a>b?a:b) #define min(a,b) (a<b?a:b) using namespace std; const int N=105; int n; int num[N]; int main() { while(scanf("%d",&n),n) { memset(num,0,sizeof(num)); int a; for(int i=1;i<=n;i++) { scanf("%d",&a); num[a]++; } if(n%2) { printf("1\n"); continue; } bool flag=true; for(int i=1;i<=100&&flag;i++) { if(num[i]%2) { printf("1\n"); flag=false; } } if(flag) printf("0\n"); } return 0; }