题解:P5640 【CSGRound2】逐梦者的初心
思路
关键在于想到怎么表示不合法的长度,用 bitset 维护反而是容易想到的。
设当前
定义不合法长度集合:
同时预处理每种字符的出现位置集合:
考虑两种操作对
尾插字符 c
原有字符的位置
对于新加入的字符,若
头插字符 c
原有字符的位置
对于新加入的字符,若
故:
维护
直接用布尔数组维护上述的操作复杂度是
bitset 一次处理约 64 位,可以将复杂度降至
用 bitset f 和 pos[c] 分别表示集合
集合平移对应左移,集合并对应按位或。
因此两种操作分别为:
// 尾插
f = (f << 1) | pos[c];
// 头插
f |= (pos[c] << k);
最终答案为:
即 f 前
代码
#include <bits/stdc++.h>
using namespace std;
const int M = 33333;
int n, m;
bitset<M> pos[1001];
bitset<M> f, mask;
int main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> n >> m;
for (int i = 0; i < n; i++)
{
int s;
cin >> s;
if (i < m)
pos[s][i] = 1;
}
int len = 0;
while (m--)
{
int opt, ch;
cin >> opt >> ch;
if (opt == 0)
f = (f << 1) | pos[ch];
else if (opt == 1)
f |= (pos[ch] << len);
len++;
mask <<= 1;
mask.set(0);
cout << len - (f & mask).count() << "\n";
}
return 0;
}