You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

63 lines
2.2 KiB

2 years ago
#include <bits/stdc++.h>
using namespace std;
const int N = 55, M = 50050; // M 包括了 50 * 1000 + 50个石子数量为1的堆数
int f[N][M];
int dfs(int a, int b) {
int &v = f[a][b];
if (~v) return v;
// 简单情况: 即所有堆的石子个数都是严格大于1此时a是0
if (!a) return v = b % 2; // 奇数为先手必胜,偶数为先手必败
// 一般5个情况 + 1个特殊情况
// 特殊情况: 如果操作后出现b中只有一堆且堆中石子个数为1
// 那么应该归入到a中并且b为0
// 以下所有情况,如果能进入必败态,先手则必胜!
if (b == 1) return dfs(a + 1, 0);
// 情况1有a从a中取一个
if (a && !dfs(a - 1, b)) return v = 1;
// 情况2, 4有b从b中取1个(石子总数 - 1) or 合并b中两堆(堆数 - 1),
if (b && !dfs(a, b - 1)) return v = 1;
// 情况3有a >= 2 合并a中两个
// 如果b的堆数不为0 a - 2, b + 1堆 + 2个石子只需要加delta ====> b + 3
// 如果b的堆数为0 a - 2, 0 + 2个石子 + 1堆 - 1 ====> b + 2
if (a >= 2 && !dfs(a - 2, b + (b ? 3 : 2))) return v = 1;
// 情况5有a有b 合并a中1个b中1个, a - 1, b的堆数无变化 + 1个石子只加delta
if (a && b && !dfs(a - 1, b + 1)) return v = 1;
// 其他情况,则先手处于必败状态
return v = 0;
}
int main() {
memset(f, -1, sizeof f);
int T, n;
cin >> T;
while (T--) {
cin >> n;
int a = 0, b = 0;
for (int i = 0; i < n; i++) {
int x;
cin >> x;
if (x == 1) a++;
// b != 0时 加1堆 + 加x石子 = 原来的 + x + 1 (其实就是区别一开始的时候)
// 当b != 0时, 我们往后加的delta
// b == 0时 加1堆 + 加x石子 = 0 + 1 + x - 1 = x
// 注意操作符优先级
else
b += b ? x + 1 : x;
}
// 1 为先手必胜, 0为先手必败
if (dfs(a, b))
puts("YES");
else
puts("NO");
}
return 0;
}