AtCoder [ABC403E] Forbidden Prefix 题解
思路
思考一个在 \(Y\) 中的字符串 \(s\) 会在什么情况下对答案有贡献。
-
\(s\) 的前缀在插入这个字符串前就已经在 \(X\) 中,那么这个字符串对答案没贡献。
-
\(s\) 的前缀在插入这个字符串后插入 \(X\) ,那么在插入这个字符串直到插入前缀之前,这个字符串都会对答案有 \(1\) 的贡献。
-
\(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;
}

浙公网安备 33010602011771号