AtCoder [ABC403E] Forbidden Prefix 题解

思路

思考一个在 \(Y\) 中的字符串 \(s\) 会在什么情况下对答案有贡献。

  1. \(s\) 的前缀在插入这个字符串前就已经在 \(X\) 中,那么这个字符串对答案没贡献。

  2. \(s\) 的前缀在插入这个字符串后插入 \(X\) ,那么在插入这个字符串直到插入前缀之前,这个字符串都会对答案有 \(1\) 的贡献。

  3. \(s\) 的前缀一直不在 \(X\) 里,那么从插入 \(s\) 起一直对答案有 \(1\) 的贡献。

那么思路就很清晰了,用hash判断,最后用差分统计答案即可,详见代码。

code

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, ans;
struct node {
	string s; int op;
}zc[200005];
map <unsigned int, int> z;
unsigned int hs[500005];
int pl[200015];

signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> zc[i].op >> zc[i].s;
	for (int i = 1; i <= n; i++) {//先hash X 中的字符串
		if (zc[i].op == 2) continue;
		int len = zc[i].s.length(); zc[i].s = " " + zc[i].s;
		for (int j = 1; j <= len; j++) hs[j] = hs[j - 1] * 131 + zc[i].s[j];
		if (!z.count(hs[len])) z[hs[len]] = i; //如果有两个相同的前缀,那么在后面插入的那个没有用
	}
	for (int i = 1; i <= n; i++) {
		if (zc[i].op == 1) continue;
		int len = zc[i].s.length(); zc[i].s = " " + zc[i].s;
		int Min = 200014;
		for (int j = 1; j <= len; j++) {
			hs[j] = hs[j - 1] * 131 + zc[i].s[j];
			if (z.count(hs[j])) Min = min(Min, z[hs[j]]);//以最前面的那个前缀为准
		}
		if (Min > i) pl[Min]--, pl[i]++;//差分
	}
	for (int i = 1; i <= n; i++) {
		ans += pl[i]; cout << ans << endl;
	}
	return 0;
}
posted @ 2025-05-02 15:55  wwqwq  阅读(32)  评论(0)    收藏  举报