【题解】[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]);
}
posted @ 2021-02-22 13:02  zrkc  阅读(60)  评论(0)    收藏  举报