#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++) { // n堆石子 int x; cin >> x; if (x == 1) a++; // 每堆石子的数量 // b==0时 加1堆+加x石子=0 + 1+x-1=x // b!=0时 加1堆+加x石子=原来的+x+1 // 偏移量是1个,在b=0时,需要考虑引入这个偏移量:-1,在b>0时,就不必再次考虑了 else b += b ? x + 1 : x; } // 1 为先手必胜, 0为先手必败 if (dfs(a, b)) puts("YES"); else puts("NO"); } return 0; }