每一堆数量都>1的话可以把合并操作和取石子看成一种操作,总操作数就是sum+n-1,为奇数就是Alice先手必胜,哪怕有一堆是2,Bob取后变为1,Alice也可以通过合并操作让1变成>1的数
可以分成两大板块a、b, a中方石子个数为1的,b中放石子个数>1的(合并操作也算进去),
共有5种操作
f(a, b)
1、a中取一个->f(a-1,b)
2、b中取一个->f(a,b-1)
3、a中合并一次,如果此时b为0->f(a-2,b+2),b非0->f(a-2, b+3)
4、b中合并一次->f(a,b-1)//与2式子相同,可化简为同一步
5、a与b合并一次->f(a-1,b+1)
注意5的操作要求a、b都大于0
接下来记忆化搜索即可
b减到1时需要划分到a堆里
cpp
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
using namespace std;
typedef pair<int, int> PII;
typedef long long ll;
const int N = 55, M = 50060;
int f[N][M];
bool dp(int a, int b)
{
int &v = f[a][b];
if(v != -1)return f[a][b];
if(!a)return v = b % 2;
if(b == 1)a ++, b --;
if(a && !dp(a - 1, b))return v = 1;
if(b && !dp(a, b - 1))return v = 1;
if(a >= 2)
{
int t = b + 2;
if(b)t ++;
if(!dp(a - 2, t))return v = 1;
}
if(a && b && !dp(a - 1, b + 1))return v = 1;
return v = 0;
}
void solve()
{
int n;
cin >> n;
int a = 0, b = 0;
for(int i = 0; i < n; i ++)
{
int x;
cin >> x;
if(x == 1)a ++;
else
{
if(b)b ++;
b += x;
}
}
if(dp(a, b))cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
IOS
memset(f, -1, sizeof f);
int _;
cin >> _;
while(_ --)
{
solve();
}
return 0;
}