Quiz Competition: Qualifiers
Quiz Competition: Qualifiers
题意简述
有 \(N\) 个参与者,最多 \(M\) 人能通过预选赛。预选赛有 \(K\) 道二选一题,答案 o 或 x。
第 \(i\) 个参与者的答案为字符串 \(S_i\),正确答案为 \(T\)。
晋级过程按 \(k = 1,2,\dots,K\) 顺序进行:
- 设当前未确定集合为 \(U\),已晋级人数为 \(pass\)。
- 令 \(c\) 为 \(U\) 中第 \(k\) 题答对的人数。
- 若 \(pass + c \le M\),则 \(U\) 中第 \(k\) 题答对的人全部晋级,\(U\) 变为 \(U\) 中第 \(k\) 题答错的人。
- 否则,\(U\) 中第 \(k\) 题答错的人全部淘汰,\(U\) 变为 \(U\) 中第 \(k\) 题答对的人。
最后仍留在 \(U\) 中的人淘汰。
有 \(Q\) 次修改,每次翻转某个参与者的某题答案,然后询问该参与者是否晋级。
约束:
- \(1 \le M \le N \le 3 \times 10^4\)
- \(1 \le K \le 200\)
- \(1 \le Q \le 5 \times 10^4\)
核心转化
把每个参与者的答题情况转化为一个长度为 \(K\) 的 01 串:
\[bit[i][k] =
\begin{cases}
1, & S_i[k] = T[k] \\
0, & S_i[k] \ne T[k]
\end{cases}
\]
修改某题答案,等价于翻转 \(bit[i][j]\)。
整个晋级过程中,未确定集合 \(U\) 始终是满足某个「前 \(k\) 题 01 模式」的参与者集合。
这个结构天然对应一棵 Trie 树。
Trie 树维护
将所有参与者的 \(bit[i]\) 插入 Trie,根到叶子的路径长度为 \(K\)。
每个节点维护:
cnt:该节点子树中参与者数量。
于是:
ch[1][cur]的cnt表示:满足当前前缀条件且下一题答对的人数。ch[0][cur]的cnt表示:满足当前前缀条件且下一题答错的人数。
#include <bits/stdc++.h>
using namespace std;
using vvi = vector<vector<int>>;
using ll = long long;
const int N = 16000005;
int ch[2][N], cnt[N];
int idx = 0;
void solve() {
int n, m, k; cin >> n >> m >> k;
string T; cin >> T;
vector<vector<uint8_t>> pari(n, vector<uint8_t>(k));
for(int i = 0; i < n; i ++) {
string s; cin >> s;
for(int j = 0; j < k; j ++) pari[i][j] = (s[j] == T[j]);
}
ch[0][0] = ch[1][0] = -1;
for(int i = 0; i < n; i++) {
int cur = 0;
cnt[cur] ++;
for(int j = 0; j < k; j ++) {
int b = pari[i][j];
if(ch[b][cur] == -1) {
idx ++;
ch[0][idx] = ch[1][idx] = -1;
ch[b][cur] = idx;
}
cur = ch[b][cur];
cnt[cur] ++;
}
}
int q; cin >> q;
while(q --) {
int x, y; cin >> x >> y; x --, y --;
int cur = 0;
for(int j = 0; j < k; j ++) {
cur = ch[pari[x][j]][cur];
cnt[cur] --;
}
pari[x][y] ^= 1;
cur = 0;
for(int j = 0; j < k; j ++) {
int b = pari[x][j];
if(ch[b][cur] == -1) {
idx ++;
ch[0][idx] = ch[1][idx] = -1;
ch[b][cur] = idx;
}
else if(cnt[ch[b][cur]] == 0) ch[0][ch[b][cur]] = ch[1][ch[b][cur]] = -1;
cur = ch[b][cur];
cnt[cur] ++;
}
cur = 0;
int pass = 0;
int flag = -1;// -1未定 0淘汰 1
for(int j = 0; j < k; j ++) {
if(cur == -1) break;
int c = (ch[1][cur] != -1 ? cnt[ch[1][cur]] : 0);
if(pass + c <= m) {
pass += c;
cur = ch[0][cur];
if(flag == -1 && pari[x][j] == 1) flag = 1;
}
else {
cur = ch[1][cur];
if(flag == -1 && pari[x][j] == 0) flag = 0;
}
}
cout << (flag == 1 ? "Yes\n" : "No\n");
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _=1; //cin >> _;
while(_--) solve();
return 0;
}

浙公网安备 33010602011771号