#include 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; }