Flag:
1. SA精通应用
2. KMP/Manacher 模板熟练(\(\color{red}{\text{GET}}\))
3. Trie/AC自动机 模板熟练。
4. 扩展KMP/字符串最小表示法(咕咕咕) 模板熟练
KMP模板:
#include
#include
#include
#include
#include
using namespace std;
int ls, lt, nxt[1000005];
char T[1000005], S[1000005];
int main(){
scanf("%s", S + 1);
scanf("%s", T + 1);
ls = strlen(S + 1);
lt = strlen(T + 1);
nxt[1] = 0;
for(int i = 2, j = 0; i <= lt; i++){
while(j != 0 && T[i] != T[j + 1]) j = nxt[j];
if(T[i] == T[j + 1]) j++;
nxt[i] = j;
}
for(int i = 1, j = 0; i <= ls; i++){
while(j == lt || (j != 0 && S[i] != T[j + 1])) j = nxt[j];
if(S[i] == T[j + 1]) j++;
if(j == lt) printf("%d\n", i - lt + 1);
}
for(int i = 1; i <= lt; i++) printf("%d ", nxt[i]);
return 0;
}
manacher模板:
#include
#include
#include
#include
#include
using namespace std;
int ls, P[23000100], ans;
char S[23000100];
int main(){
S[0] = '$';
char ch = getchar();
while(ch >= 'a' && ch <= 'z') S[++ls] = '#', S[++ls] = ch, ch = getchar();
S[++ls] = '#'; S[++ls] = '^';
for(int i = 1, R = 0 , now = 0; i <= ls; i++){
if(i <= R) P[i] = min(P[now + now - i], R - i);
else P[i] = 0;
while(S[i + P[i] + 1] == S[i - P[i] -1]) P[i]++;
if(P[i] + i > R) R = P[i] + i, now = i;
ans = max(ans, P[i]);
}
cout << ans << endl;
return 0;
}
Trie模板:
#include
#include
#include
#include
#include
using namespace std;
struct trie{
struct node{
int ch[26], cnt, bj;
}t[510005];
int tot, rt;
int NEW(){
return ++tot;
}
void change(char *S, int ls){
int now = (rt = rt == 0 ? NEW() : rt);
for(int i = 1; i <= ls; i++){
int z = S[i] - 'a';
if(t[now].ch[z] == 0)
t[now].ch[z] = NEW();
now = t[now].ch[z];
}
t[now].cnt++;
}
int query(char *S, int ls){
int now = (rt = rt == 0 ? NEW() : rt);
for(int i = 1; i <= ls; i++){
int z = S[i] - 'a';
if(t[now].ch[z] == 0) return -1;
now = t[now].ch[z];
}
if(t[now].cnt == 0) return -1;
if(t[now].bj == 1) return 1;
t[now].bj = 1;
return 0;
}
}TR;
int z, ls, n;
char S[510005];
int main(){
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%s", S + 1);
ls = strlen(S + 1);
TR.change(S, ls);
}
scanf("%d", &n);
for(int i = 1; i <= n; i++){
scanf("%s", S + 1);
ls = strlen(S + 1);
int op = TR.query(S, ls);
if(op == 1) puts("REPEAT");
if(op == 0) puts("OK");
if(op == -1) puts("WRONG");
}
}
AC自动机:
Trie图(AC自动机无fail指针,孩子如果为空直接指到相应的该去的差了好几次的有儿子的fail上)、fail树
注意判是否出现过要沿着\(fail\)找一遍。
struct AC_machine{
struct node{
int ch[26], nxt, cnt, bj;
}t[3000005];
int rt, tot;
int NEW(){
++tot;
memset(t[tot].ch, 0, sizeof(t[tot].ch));
t[tot].nxt = t[tot].cnt = t[tot].bj = 0;
return tot;
}
void clear(){
tot = rt = 0;
}
void change(char *S, int ls){
int now = (rt = rt == 0 ? NEW() : rt);
for(int i = 1; i <= ls; i++){
int z = S[i] - 'a';
if(t[now].ch[z] == 0)
t[now].ch[z] = NEW();
now = t[now].ch[z];
}
t[now].bj = ++bh;
}
void init(){
Q.push(rt);
while(Q.size()){
int now = Q.front();
Q.pop();
for(int i = 0; i < 26; i++){
if(t[now].ch[i] == 0) continue;
int p = t[now].nxt;
while(p != 0 && t[p].ch[i] == 0) p = t[p].nxt;
if(p != 0) t[t[now].ch[i]].nxt= t[p].ch[i];
else t[t[now].ch[i]].nxt = rt;
Q.push(t[now].ch[i]);
}
}
}
int query(char *S, int ls){
int ans = 0;
int now = rt;
for(int i = 1; i <= ls; i++){
int z = S[i] - 'a';
while(now != rt && t[now].ch[z] == 0) now = t[now].nxt;
if(t[now].ch[z] == 0) continue;
now = t[now].ch[z];
int p = now;
while(p != rt){
if(t[p].bj) t[p].cnt++;
if(ans < t[p].cnt){
ans = t[p].cnt;
V.clear();
}
if(ans == t[p].cnt) V.push_back(t[p].bj);
p = t[p].nxt;
}
}
return ans;
}
}ACM;
后缀数组模板:
#include
#include
#include
#include
#include
using namespace std;
struct suffix_array{
int rk[2000005], sa[2000005], hr[2000005],/*(height)*/ hs[2000005];/*(h)*/
int bin[2000005], sz, tmp[2000005];
void build(char *S, int ls){
sz = max(ls, 255);
for(int i = 1; i <= ls; i++) rk[i] = S[i] + 1;
for(int i = 1; i <= sz; i++) bin[i] = 0;
for(int i = 1; i <= ls; i++) bin[rk[i]]++;
for(int i = 2; i <= sz; i++) bin[i] += bin[i - 1];
for(int i = ls; i >= 1; i--) sa[bin[rk[i]]--] = i;
for(int j = 1; j <= ls; j <<= 1){
int tot = 0;
for(int i = ls - j + 1; i <= ls; i++) tmp[++tot] = i;
for(int i = 1; i <= ls; i++) if(sa[i] - j > 0) tmp[++tot] = sa[i] - j;
for(int i = 1; i <= sz; i++) bin[i] = 0;
for(int i = 1; i <= sz; i++) bin[rk[i]]++;
for(int i = 2; i <= sz; i++) bin[i] += bin[i - 1];
for(int i = ls; i >= 1; i--) sa[bin[rk[tmp[i]]]--] = tmp[i];
tot = 1; tmp[sa[1]] = 1;
for(int i = 2; i <= ls; i++)
tmp[sa[i]] = rk[sa[i - 1] + j] == rk[sa[i] + j] && rk[sa[i - 1]] == rk[sa[i]] ? tot : ++tot;
for(int i = 1; i <= ls; i++) rk[i] = tmp[i];
if(tot == ls) break;
}
for(int i = 1; i <= ls; i++){
hs[i] = max(hs[i] - 1, 0);
while(S[i + hs[i]] == S[sa[rk[i] - 1] + hs[i]]) hs[i]++;
hr[rk[i]] = hs[i];
}
}
}SA;
char S[2000005];
int main() {
scanf("%s", S + 1);
int ls = strlen(S + 1);
SA.build(S, ls);
for(int i = 1; i <= ls; i++)
printf("%d ", SA.sa[i]);
return 0;
}