bzoj3895: 取石子(博弈论,记忆化搜索)
3895: 取石子
Time Limit: 1 Sec Memory Limit: 512 MBSubmit: 361 Solved: 177
[Submit][Status][Discuss]
Description
Alice和Bob两个好朋含友又开始玩取石子了。游戏开始时,有N堆石子
排成一排,然后他们轮流操作(Alice先手),每次操作时从下面的规则中任选一个:
·从某堆石子中取走一个
·合并任意两堆石子
不能操作的人输。Alice想知道,她是否能有必胜策略。
Input
第一行输入T,表示数据组数。
对于每组测试数据,第一行读入N。
接下来N个正整数a1,a2…an,表示每堆石子的数量。
Output
对于每组测试数据,输出一行。
输出YES表示Alice有必胜策略,输出NO表示Alice没有必胜策略。
Sample Input
3
3
1 1 2
2
3 4
3
2 3 5
3
1 1 2
2
3 4
3
2 3 5
Sample Output
YES
NO
NO
NO
NO
HINT
100%的数据满足T<=100, N<=50. ai<=1000
思路:
本来想纯粹博弈论,结果发现最终有的情况数不确定,所以只能搜索一波
因为无论何时,只要每堆都有石子,合并的结果都一样
所以我们把每一堆石子都先取成1
然后剩下这么多堆为1的石子,,每次操作有两种选择,要么合并,要么取走这一堆
然后就结束了
维护选用记忆化搜索
代码:
#include<iostream> #include<cstdio> #include<cstring> #define rii register int i using namespace std; int n,dp[55][50055],t,x,l,r,bj[55][50055]; int dplast(int l,int r) { if(l==0) { return r&1; } if(r==1) { return dplast(l+1,0); } if(bj[l][r]) { return dp[l][r]; bj[l][r]=1; } if(l&&!dplast(l-1,r)) { return dp[l][r]=1; } if(l&&r&&!dplast(l-1,r+1)) { return dp[l][r]=1; } if(l>=2&&!dplast(l-2,r+2+(r?1:0))) { return dp[l][r]=1; } if(r&&!dplast(l,r-1)) { return dp[l][r]=1; } return dp[l][r]=0; } int main() { scanf("%d",&t); while(t--) { scanf("%d",&n); l=0; r=-1; for(rii=1;i<=n;i++) { scanf("%d",&x); if(x==1) { l++; } else { r+=x+1; } if(r==-1) { r=0; } } if(dplast(l,r)==1) { printf("YES\n"); } else { printf("NO\n"); } } }