luogu4595 [COCI2011-2012#5] POPLOCAVANJE 后缀自动机
看着就像后缀自动机....
然后搜了一下,网上一大把的\(AC\)自动机
嗯......
不管了,打一个试试
然后就过了\(QAQ\)
我们考虑对于每个点\(i\)求出它往前最长能匹配的子串的长度
可以对街道串建出后缀自动机
把所有的\(L\)在后缀自动机上走
走到的串就打个标记,最后顺着\(parent\)树下传一遍即可
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
#define ri register int
#define ll long long
#define rep(io, st, ed) for(ri io = st; io <= ed; io ++)
#define drep(io, ed, st) for(ri io = ed; io >= st; io --)
const int sid = 500060;
char s[sid];
int n, m, id = 1;
int fa[sid], mx[sid], val[sid], rig[sid];
int go[sid][26];
int extend(int lst, int c, int pos) {
int p = lst, np = ++ id;
rig[np] = pos; mx[np] = mx[p] + 1;
for( ; p && !go[p][c]; p = fa[p])
go[p][c] = np;
if(!p) fa[np] = 1;
else {
int q = go[p][c];
if(mx[p] + 1 == mx[q]) fa[np] = q;
else {
int nq = ++ id;
mx[nq] = mx[p] + 1;
fa[nq] = fa[q]; fa[np] = fa[q] = nq;
memcpy(go[nq], go[q], sizeof(go[q]));
for( ; p && go[p][c] == q; p = fa[p])
go[p][c] = nq;
}
}
return np;
}
void find(char *s) {
int n = strlen(s + 1);
int now = 1;
rep(i, 1, n) {
int opt = s[i] - 'a';
if(!go[now][opt]) return;
now = go[now][opt];
}
val[now] = max(val[now], n);
}
int nc[sid], ip[sid], na[sid];
void solve() {
rep(i, 1, id) nc[mx[i]] ++;
rep(i, 1, n) nc[i] += nc[i - 1];
rep(i, 1, id) ip[nc[mx[i]] --] = i;
rep(i, 1, id) {
int o = ip[i];
val[o] = max(val[o], val[fa[o]]);
if(rig[o]) {
int L = rig[o] - val[o] + 1, R = rig[o];
na[L] ++; na[R + 1] --;
}
}
rep(i, 1, n) na[i] += na[i - 1];
int ans = 0;
rep(i, 1, n) if(!na[i]) ans ++;
printf("%d\n", ans);
}
int main() {
cin >> n;
scanf("%s", s + 1);
int lst = 1;
rep(i, 1, n) lst = extend(lst, s[i] - 'a', i);
cin >> m;
rep(i, 1, m) {
scanf("%s", s + 1);
find(s);
}
solve();
return 0;
}
不知道为啥机房的人之后都写了后缀自动机....
喵喵喵?喵喵喵! 喵喵喵......