字符串专题

Flag:

1. SA精通应用

2. KMP/Manacher 模板熟练(\(\color{red}{\text{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\n", 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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值