[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 秒。

浙公网安备 33010602011771号