题目大意:
给出 n 个串(len <= 100), 再给出一个主串(len <= 100000), 给出 Q 次询问, 每次包括一个整数和一个字母,求主串在该整数位置将字母改为该字母后,n个串再主串中出现的次数。
输入简述 :
输入N <= 1000, Q <= 200000, N 个串,一个主串, Q次询问的整数和字母。
输出简述 :
最初值 + Q次询问的答案。
sample input :
3 5
ab
bc
abc
acbcb
2 b
3 c
4 a
1 b
3 a
sample ouput :
1
2
3
4
2
1
题解 :
提说这是 NOI 测试的签到题, 看来还是我太弱了。
我们考虑每次修改对答案的影响, 每次修改我们只会影响 pos - len + 1 到 pos + len - 1 的值, len 为非主串的字符串长度, pos为修改的位置, 于是我们只需要求出在这段区间的值就可以了, 那我们这里就会跑两边 AC 自动机,由于 len 不超过 100, 但我们会多次跳 fail, 所以这里可能会超, 于是我们考虑优化,我们将每个 AC 自动机上的点, 把他们所有的 fail 指针所跳的点的 cnt 都加起来,在预处理完成,这样我们就不用跳 fail 了。
代码 :
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <ctime>
#include <map>
#include <vector>
#include <queue>
#define clr(a) memset(a, 0, sizeof(a))
using namespace std;
inline int read() {
int i = 0, f = 1;
char ch = getchar();
while(!isdigit(ch)) {
if(ch == '-') f = -1; ch = getchar();
}
while(isdigit(ch)) {
i = (i << 3) + (i << 1) + ch - '0'; ch = getchar();
}
return i * f;
}
const int MAXN = 1e5 + 5;
int mx;
char s[MAXN];
struct AC {
int tot;
struct point {
int trans[26], cnt, fail;
void clear() {
clr(trans); cnt = fail = 0;
}
} tr[MAXN * 10];
inline void init() {
for(int i = 0; i < 26; ++i) tr[0].trans[i] = 1;
tr[tot = 1].clear();
}
inline void insert(char * s) {
int u = 1;
int len = strlen(s + 1); mx = max(mx, len);
for(int i = 1; i <= len; ++i) {
if(!tr[u].trans[s[i] - 'a']) tr[tr[u].trans[s[i] - 'a'] = ++tot].clear();
u = tr[u].trans[s[i] - 'a'];
}
tr[u].cnt++;
}
inline void buildfail() {
queue<int> q;
q.push(1);
while(!q.empty()) {
int u = q.front(); q.pop();
for(int i = 0; i < 26; ++i) {
int v = tr[u].fail;
while(!tr[v].trans[i]) v = tr[v].fail;
v = tr[v].trans[i]; int w = tr[u].trans[i];
if(w) tr[w].fail = v, q.push(w), tr[w].cnt += tr[v].cnt;
else tr[u].trans[i] = v;
}
}
}
inline int solve(char *s, int l, int r) {
int now = 1, ans = 0;
for(int i = l; i <= r; ++i) {
now = tr[now].trans[s[i] - 'a'];
ans += tr[now].cnt;
}
return ans;
}
}acam;
int main() {
//freopen("1.in", "r", stdin);
int n = read(), m = read();
acam.init();
for(int i = 1; i <= n; ++i) scanf("%s", s + 1), acam.insert(s);
acam.buildfail();
scanf("%s", s + 1); int len = strlen(s + 1);
int ans = acam.solve(s, 1, len);
printf("%d\n", ans);
while(m--) {
int pos = read(); char ch = getchar();
int ans1 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1));
s[pos] = ch;
int ans2 = acam.solve(s, max(1, pos - mx + 1), min(len, pos + mx - 1));
ans += ans2 - ans1;
cout<<ans<<'\n';
}
}