字符串专题

Flag:

1. SA精通应用

2. KMP/Manacher 模板熟练((color{red}{ ext{GET}})

3. Trie/AC自动机 模板熟练。

4. 扩展KMP/字符串最小表示法(咕咕咕) 模板熟练

KMP模板:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
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
", i - lt + 1);
	}
	for(int i = 1; i <= lt; i++) printf("%d ", nxt[i]);
	return 0;
}

manacher模板:

#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
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 <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
#include <algorithm>
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 <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
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;
}
原文地址:https://www.cnblogs.com/Smeow/p/10578488.html