[SG + 状压] P2575 高手过招 题解

首先发现数据范围极小,想到可能有状压因素。

细看题面,这题还有一个博弈论的思想,而且这 \(n\) 行实际上毫无关联。因此想到,用 SG 定理直接合并 \(n\) 行的状态。

具体实现的话,我们预处理这 20 个格子,状压出棋子放置所有的状态的 SG 函数即可。

预处理复杂度 \(O(2 ^ {20} \times 20)\) ,有可能在处理棋子跳过棋子的时候浪费时间,但是实际上跑不满。

计算答案复杂度 \(O(Tnm)\) , 与输入是同量级。

#include <bits/stdc++.h>
constexpr int N = 25;
using namespace std;
int t , n , m , x , ans , process , p[N] , g[1 << N];
set <int> check;
inline void init() {
	for(register int i = (1 << 20) - 1; i >= 0; --i) {
		check.clear();
		for(register int j = 0; j < 19; ++j) {
			if(!(i & (1 << j))) {continue;}
			int nxt;
			if(!(i & (1 << j + 1))) {
				nxt = i ^ (1 << j) ^ (1 << j + 1);
				check.insert(g[nxt]);
			}
			else {
				for(register int k = j + 2; k < 20; ++k) {
					if(!(i & (1 << k))) {
						nxt = i ^ (1 << j) ^ (1 << k);
						check.insert(g[nxt]);
						break;
					}
				}
			}
		}
		register int j = 0;
		while(check.count(j)) {++j;}
		g[i] = j;
	}
}
inline void solve() {
	ans = process = 0;
	cin >> n;
	for(register int i = 1; i <= n; ++i) {
        process = 0;
		cin >> m;
		for(register int i = 1; i <= m; ++i) {
			cin >> p[i];
			process += (1 << p[i] - 1);
		}
		ans ^= g[process];
	}
	cout << (ans ? "YES" : "NO") << '\n';
}
int main() {
    ios :: sync_with_stdio(0) , cin.tie(0) , cout.tie(0);
	init();
	cin >> t;
	while(t--) {solve();}
	return 0;
}

总用时 3.09 秒。

posted @ 2025-07-25 19:49  風月華  阅读(53)  评论(0)    收藏  举报