【题解】[USACO15FEB]Censoring S
[USACO15FEB]Censoring S
本来只是在 KMP 那篇里面提一下的...后来看了题解感觉我的方法不太优啊...
栈实在是太强了!(然而总以为栈没什么用,现在感觉,这种顺序遍历又能删除段的题,是不是很符合栈呢?)
题意
一个字符串 S ,删除其中的子串 T (注意到删除之后,两端的字符串有可能会拼接出来一个新的子串 T ),不断重复这一过程,直到 S 中不存在子串 T ,输出 T
样例
input #1
whatthemomooofun
moo
output #1
whatthefun
题解
第一反应:\(hash[prei] = \Sigma\ h_i\times base^i\) ,把所有前缀的哈希值用数据结构维护,每次查询到值为 \(hash[prei] - hash[T]\) 就把这一串删掉。用权值线段树做应该可以。
然而我是从 KMP 来的,所以没这么写(
考虑 KMP 的匹配过程。注意到对于 S 串,每个位置在失配函数(状态机)上都有一个对应状态(f[i] ,含义即可匹配的最大长度)。若当前匹配成功,当前串删除,等价于状态退回到这个串之前的位置,然后继续匹配。
这个串之前的位置?如果能动态清零区间,查询区间和,就能二分查找那个位置了。线段树做,\(O(nlgnlgn)\) 。
然而能够 \(O(n)\) ...把 S 串丢到栈里,匹配成功就弹出匹配部分,从栈顶的状态继续匹配...太正解了
(那么 hash+栈 也挺好的了qwq )
原来的代码就放这了
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 1000005;
int N, M; char S[MAXN], T[MAXN];
int f[MAXN], stt[MAXN]; // state
int flg[MAXN], cut[MAXN];
struct segmemtTree {
#define lson (x<<1)
#define rson (x<<1|1)
int sum[MAXN<<2], tag[MAXN<<2];
void pushup(int x) { sum[x] = sum[lson] + sum[rson]; }
void pushdown(int x) {
if (tag[x]) sum[lson] = 0, sum[rson] = 0;
tag[lson] |= tag[x], tag[rson] |= tag[x];
tag[x] = 0;
}
void build(int x, int l, int r) {
if (l==r) sum[x] = 1, tag[x] = 0;
else {
int mid = (l + r) >> 1;
build(lson, l, mid), build(rson, mid+1, r);
pushup(x);
}
}
void cover(int x, int l, int r, int _l, int _r) {
if (l>=_l && r<=_r) sum[x] = 0, tag[x] = 1;
else {
int mid = (l + r) >> 1;
pushdown(x);
if (mid>=_l) cover(lson, l, mid, _l, _r);
if (mid< _r) cover(rson, mid+1, r, _l, _r);
pushup(x);
}
}
int query(int x, int l, int r, int _l, int _r) {
if (l>=_l && r<=_r) return sum[x];
else {
pushdown(x);
int mid = (l + r) >> 1, tmp = 0;
if (mid>=_l) tmp += query(lson, l, mid, _l, _r);
if (mid< _r) tmp += query(rson, mid+1, r, _l, _r);
return tmp;
}
}
} ST;
int main()
{
scanf("%s%s", S, T); N = strlen(S), M = strlen(T);
f[0] = 0, f[1] = 0;
for (int i=1; i< M; i++) {
int j = f[i];
while (j && T[j]!=T[i]) j = f[j];
f[i+1] = T[i]==T[j] ? j+1 : 0;
}
ST.build(1, 1, N);
int j = 0;
for (int i=0; i< N; i++) {
while (j && T[j]!=S[i]) j = f[j];
if (T[j]==S[i]) j++;
stt[i] = j;
if (j==M) {
flg[i] = 1; // 被删串末尾打个标记,之后倒序处理串
//j = stt[i-M];
int l = 1, r = i+1; // [l, r)
while (r - l > 1) {
int mid = (l + r) >> 1;
if (ST.query(1, 1, N, mid, i)<M+1) r = mid;
else l = mid;
}
j = stt[l];
l = 1, r = i+1; // (l, r]
while (r - l > 1) {
int mid = (l + r) >> 1;
if (ST.query(1, 1, N, mid, i)<M) r = mid;
else l = mid;
}
ST.cover(1, 1, N, l, i);
}
}
//for (int i=0; i< N; i++) printf("%d", flg[i]); puts("");
int len = 0;
for (int i=N-1; i>=0; i--) {
if (flg[i]) len += M;
if (len) cut[i] = 1;
if (len) len--;
}
for (int i=0; i< N; i++) if (!cut[i]) printf("%c", S[i]);
}

关于 KMP 匹配的“状态”。栈太强了,我太菜了
浙公网安备 33010602011771号