1668:取石子
时间限制: 1000 ms 内存限制: 524288 KB【题目描述】
Alice 和 Bob 两个好朋友又开始玩取石子了。游戏开始时,有 NN 堆石子排成一排,然后他们轮流操作(Alice 先手),每次操作时从下面的规则中任选一个:
1、从某堆石子中取走一个;
2、合并任意两堆石子。
不能操作的人输。Alice 想知道,她是否能有必胜策略。
【输入】
第一行输入 T,表示数据组数。
对于每组测试数据,第一行读入 N;
接下来 N 个正整数 a1,a2,⋯,an,表示每堆石子的数量。
【输出】
对于每组测试数据,输出一行。
输出 YES 表示 Alice 有必胜策略,输出 NO 表示 Alice 没有必胜策略。
【输入样例】
3
3
1 1 2
2
3 4
3
2 3 5
【输出样例】
YES
NO
NO
【提示】
数据范围与提示:
对于全部数据,T≤100,N≤50,ai≤1000。
sol:貌似和博弈论没有半毛钱关系
如果没有1的堆,那么判断一下总操作数的奇偶性即可,烦就烦在有1,
题解上说是记搜,分四种情况(具体见注释),不知道为什么n=50都能过qaq
#include <bits/stdc++.h> using namespace std; typedef int ll; inline ll read() { ll s=0; bool f=0; char ch=' '; while(!isdigit(ch)) { f|=(ch=='-'); ch=getchar(); } while(isdigit(ch)) { s=(s<<3)+(s<<1)+(ch^48); ch=getchar(); } return (f)?(-s):(s); } #define R(x) x=read() inline void write(ll x) { if(x<0) { putchar('-'); x=-x; } if(x<10) { putchar(x+'0'); return; } write(x/10); putchar((x%10)+'0'); return; } #define W(x) write(x),putchar(' ') #define Wl(x) write(x),putchar('\n') const int N=55; int T; int n,A[N]; int Bo[N][N*1000]; inline bool dfs(int Num1,int Step) { if(Bo[Num1][Step]!=-1) return Bo[Num1][Step]; if(Num1==0) return Bo[Num1][Step]=((Step&1)?1:0); if(Step==1) return Bo[Num1][Step]=dfs(Num1+1,0); if(Num1&&(!dfs(Num1-1,Step))) return Bo[Num1][Step]=1; //取走一个1 if(Num1>=2&&(!dfs(Num1-2,Step+2+(Step?1:0)))) return Bo[Num1][Step]=1; //合并两个1 if(Num1&&Step&&(!dfs(Num1-1,Step+1))) return Bo[Num1][Step]=1; //把一个1合并到非1堆中 if(Step&&(!dfs(Num1,Step-1))) return Bo[Num1][Step]=1; //合并两个大堆或取走一个 return Bo[Num1][Step]=0; } int main() { R(T); memset(Bo,-1,sizeof Bo); while(T--) { int i,Sum=-1,cnt=0; R(n); for(i=1;i<=n;i++) { A[i]=read(); if(A[i]==1) cnt++; else Sum+=A[i]+1; } if(!cnt) { if(Sum&1) puts("YES"); else puts("NO"); continue; } Sum=max(Sum,0); if(dfs(cnt,Sum)) puts("YES"); else puts("NO"); } return 0; } /* input3 5 3 2 1 3 4 1 1 1 1 2 1 3 5 1 2 1 2 2 3 1 1 1 output YES YES YES NO NO */