字符串板子合集

KMP and border

image-20250831231617551

#include<algorithm>
#include<cstring>
#include<cstdio>
#define ll long long
#define MaxN 20005000
using namespace std;
void zkmp(char *a,int n,int *z)
{
  z[1]=n;
  for (int i=2,l=0,r=0;i<=n;i++){
    z[i]=(r<i) ? 0 : min(z[i-l+1],r-i+1);
    while(i+z[i]<=n&&a[i+z[i]]==a[z[i]+1])z[i]++;
    if (i+z[i]-1>r){l=i;r=i+z[i]-1;}
  }
}
void zmatch(char *a,int na,char *b,int nb,int *z,int *p)
{
  for (int i=1,l=0,r=0;i<=na;i++){
    p[i]=(r<i) ? 0 : min(z[i-l+1],r-i+1);
    while(i+p[i]<=na&&a[i+p[i]]==b[p[i]+1])p[i]++;
    if (i+p[i]-1>r){l=i;r=i+p[i]-1;}
  }
}
char a[MaxN],b[MaxN];
int z[MaxN],p[MaxN];
void calc(int *z,int n)
{
  ll ans=0;
  for (int i=1;i<=n;i++)
    ans^=1ll*i*(z[i]+1);
  printf("%lld\n",ans);
}
int main()
{
  scanf("%s%s",a+1,b+1);
  int na=strlen(a+1),nb=strlen(b+1);
  zkmp(b,nb,z);calc(z,nb);
  zmatch(a,na,b,nb,z,p);calc(p,na);
  return 0;
}

image-20250831231701980
image-20250831231736015
image-20250831231830460

image-20250831231843770image-20250831231847940

image-20250831231913770image-20250831231918482

AC(打字机)

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e5 + 10;
int m;
struct node
{
    int y, nex;
} e[maxn << 1];
int head[maxn], tot;
void add(int x, int y)
{
    e[++tot] = {y, head[x]};
    head[x] = tot;
}
char s[maxn];
int ans[maxn];
int pos[maxn];
int fail[maxn];
int trie[maxn << 1][26], cnt;
int t[maxn << 1];
int lowbit(int x)
{
    return x & (-x);
}
vector<pair<int, int>> ques[maxn];
int sta[maxn];
vector<int> ed[maxn];
int crk;
int siz[maxn];
int trie_2[maxn << 1][26];
int num[maxn];
void Insert(char *s)
{
    int p = 0, len = strlen(s), tp = 0;
    for (int i = 0; i < len; i++)
    {
        if (s[i] != 'B' && s[i] != 'P')
        {
            int ch = s[i] - 'a';
            if (!trie[p][ch])
                trie[p][ch] = ++cnt;
            sta[++tp] = trie[p][ch];
            p = trie[p][ch];
        }
        else if (s[i] == 'B')
        {
            tp--;
            p = sta[tp];
        }
        else if (s[i] == 'P')
        {
            ed[p].push_back(++crk);
            pos[crk] = p;
        }
    }
}
void build()
{
    memcpy(trie_2, trie, sizeof(trie));
    queue<int> q;
    for (int i = 0; i < 26; i++)
        if (trie_2[0][i])
            q.push(trie_2[0][i]), fail[trie_2[0][i]] = 0;
    while (!q.empty())
    {
        int u = q.front();
        q.pop();
        for (int i = 0; i < 26; i++)
        {
            if (trie_2[u][i])
                fail[trie_2[u][i]] = trie_2[fail[u]][i], q.push(trie_2[u][i]);
            else
                trie_2[u][i] = trie_2[fail[u]][i];
        }
    }
}
void modify(int x, int num)
{
    for (; x <= cnt + 1; x += lowbit(x))
        t[x] += num;
}
int ask(int x)
{
    int res = 0;
    for (; x; x -= lowbit(x))
        res += t[x];
    return res;
}
int sum_ask(int l, int r)
{
    return ask(r) - ask(l - 1);
}
int cnt_2, dfn[maxn];
void dfsa(int x, int fa)
{
    dfn[x] = ++cnt_2;
    siz[x] = 1;
    for (int i = head[x]; i; i = e[i].nex)
    {
        int y = e[i].y;
        if (y == fa)
            continue;
        dfsa(y, x);
        siz[x] += siz[y];
    }
    return;
}
void dfsb(int x)
{
    for (int i = 0; i < ed[x].size(); i++)
        num[ed[x][i]]++;
    modify(dfn[fail[x]], 1);
    for (int i = 0; i < ques[x].size(); i++)
    {
        pair<int, int> now = ques[x][i];
        ans[now.second] = num[now.first] + sum_ask(dfn[pos[now.first]], dfn[pos[now.first]] + siz[pos[now.first]] - 1);
    }
    for (int i = 0; i < 26; i++)
        if (trie[x][i])
            dfsb(trie[x][i]);
    for (int i = 0; i < ed[x].size(); i++)
        num[ed[x][i]]--;
    modify(dfn[fail[x]], -1);
}
signed main()
{
    ios::sync_with_stdio(false);
    cin >> s + 1;
    Insert(s + 1);
    build();
    cin >> m;
    for (int i = 1; i <= m; i++)
    {
        int x, y;
        cin >> x >> y;
        ques[pos[y]].push_back(make_pair(x, i));
    }
    for (int i = 1; i <= cnt; i++)
    {
        add(i, fail[i]);
        add(fail[i], i);
    }
    dfsa(0, -1);
    dfsb(0);
    for (int i = 1; i <= m; i++)
        cout << ans[i] << endl;
    return 0;
}

manacher

#include <bits/stdc++.h>
using namespace std;

const int maxn = 11000100;

int n, l[maxn << 1], ans, m;
char t[maxn], s[maxn << 1];

void init() {
    s[0] = s[++n] = '|';
    for (int i = 1; i <= m; i++)
        s[++n] = t[i], s[++n] = '|';
    s[++n] = '@';
}

void manacher() {
    int p = 0, mx = 0;
    for (int i = 2; i < n; i++) {
        if (i < mx)
            l[i] = min(l[p * 2 - i], mx - i);
        else
            l[i] = 1;
        while (s[i + l[i]] == s[i - l[i]])
            l[i]++;
        if (i + l[i] > mx)
            mx = i + l[i], p = i;
        ans = max(ans, l[i] - 1);
    }
}

signed main() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> t + 1;
    m = strlen(t + 1);
    init();
    manacher();
    cout << ans << endl;
    return 0;
}

PAM

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define pii pair<int, int>
#define mp make_pair
#define db double
const int maxn = 2e6 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

namespace IO {
void openfile() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
}
void Min(int& x, int y) {
    x = (x < y) ? x : y;
}
void Max(int& x, int y) {
    x = (x > y) ? x : y;
}
int add(int x, int y) {
    return (x + y) >= mod ? (x + y - mod) : (x + y);
}
int sub(int x, int y) {
    return (x < y) ? (x + mod - y) : (x - y);
}
void Add(int& x, int y) {
    x = (x + y) >= mod ? (x + y - mod) : (x + y);
}
void Sub(int& x, int y) {
    x = (x < y) ? (x - y + mod) : (x - y);
}
int mul(int x, int y) {
    return 1ll * x * y % mod;
}
void Mul(int& x, int y) {
    x = 1ll * x * y % mod;
}
int qpow(int x, int y = mod - 2) {
    int ans = 1;
    while (y) {
        if (y & 1)
            ans = 1ll * x * ans % mod;
        x = 1ll * x * x % mod, y >>= 1;
    }
    return ans;
}
inline int read() {
    int x = 0, f = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    if (f)
        x = -x;
    return x;
}
}  // namespace IO
using namespace IO;

int n, lst, ch[maxn][26], len[maxn], num[maxn], fail[maxn], cur, pos, tot = 1;
char s[maxn];

int getfail(int x, int i) {
    while (i - len[x] - 1 < 0 || s[i - len[x] - 1] != s[i])
        x = fail[x];
    return x;
}

signed main() {
    openfile();
    ios::sync_with_stdio(false), cin.tie(0);
    cin >> s, n = strlen(s);
    len[1] = -1, fail[0] = 1;
    for (int i = 0; i < n; i++) {
        if (i)
            s[i] = (s[i] - 97 + lst) % 26 + 97;
        pos = getfail(cur, i);
        int op = s[i] - 'a';
        if (!ch[pos][op]) {
            fail[++tot] = ch[getfail(fail[pos], i)][op];
            ch[pos][op] = tot;
            len[tot] = len[pos] + 2;
            num[tot] = num[fail[tot]] + 1;
        }
        cur = ch[pos][op];
        cout << (lst = num[cur]) << ' ';
    }
    return 0;
}

SA

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 1e6 + 10;
int n, sa[maxn], x[maxn], y[maxn], rk[maxn], height[maxn], m, c[maxn];
/*
sa:排名为i的是哪一个后缀
x:第一关键字
y:第二关键字
rk:第i个后缀的排名
height:排名第i的后缀和排名第i-1的后缀的LCP
c:基数排序的时候所要用到的桶
*/
char s[maxn];
void get_sa() {
    /* 这个地方要用到基数排序来进行求组 */
    for (int i = 1; i <= n; i++)
        ++c[x[i] = s[i]];  // 将每一个数放在我们的桶里
    for (int i = 2; i <= m; i++)
        c[i] += c[i - 1];  // 前缀和,基数排序的时候要用到
    for (int i = n; i; i--)
        sa[c[x[i]]--] = i;  // 基数排序
    for (int k = 1; k <= n; k <<= 1) {
        int num = 0;
        for (int i = n - k + 1; i <= n; i++)
            y[++num] = i;  // 如果并没有第二关键字的话就直接放在桶里面(并不需要考虑顺序
        for (int i = 1; i <= n; i++)
            if (sa[i] > k)
                y[++num] = sa[i] - k;  // 按照sa的顺序把后缀插进去
        for (int i = 1; i <= m; i++)
            c[i] = 0;  // 清空
        for (int i = 1; i <= n; i++)
            c[x[i]]++;  // 桶++
        for (int i = 2; i <= m; i++)
            c[i] += c[i - 1];  // 前缀和
        for (int i = n; i; i--)
            sa[c[x[y[i]]]--] = y[i], y[i] = 0;
        // 基数排序,按照第二关键字的顺序进行排序就可以保证我们的第一关键字相同的时候第二关键字小的在前面
        swap(x, y);
        // 因为我们当前的y已经没用了,所以我们直接把x和y进行交换就可以不用再写一个循环清空x了
        num = 1;
        x[sa[1]] = 1;  // 先把顺序在第一个的处理
        for (int i = 2; i <= n; i++)
            x[sa[i]] = (y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) ? num : ++num;
        // 如果这个后缀的两个关键字都是一样的那么不需要更新我们的rk
         if (num == n)
             break;
        // 如果我们的num已经是n了说明我们已经更新了n次,那么说明我们所有的后缀应该都到了自己应该在的地方就不需要进行多余的循环了
        m = num;
        // 如果并没有结束我们的循环的话我们就还需要进行循环,那么我们就可以将我们的m更新为现在还有多少个不相同的后缀,那么我们下一次的m就可以直接更新为不相同的数目。但是亲测m=n也是可以过的(似乎没有人会去卡这个东西
    }
}
void get_height() {
    for (int i = 1; i <= n; i++)
        rk[sa[i]] = i;  // 排名是i的字符串的排名是i(废话
    for (int i = 1, k = 0; i <= n; i++) {
        if (rk[i] == 1)  // height[1]=0
            continue;
        if (k)
            --k;
        // 性质:height[rk[i]]>=height[rk[i-1]]-1
        int j = sa[rk[i] - 1];  // 排名是rk[i]-1的后缀
        while (i + k <= n && j + k <= n && s[i + k] == s[j + k])
            k++;            // 暴力向后匹配
        height[rk[i]] = k;  // 更新
    }
}
signed main() {
    ios::sync_with_stdio(false);
    cin >> s + 1;
    n = strlen(s + 1);
    m = 122;
    get_sa();
    get_height();
    for (int i = 1; i <= n; i++)
        cout << sa[i] << ' ';
    cout << endl;
    for (int i = 1; i <= n; i++)
        cout << height[i] << ' ';
    cout << endl;
    return 0;
}

SAM

#include <bits/stdc++.h>
using namespace std;

#define ll long long
#define pii pair<int, int>
#define mp make_pair
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;

namespace IO {
void openfile() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
}

int add(int x, int y) {
    x += y;
    return x >= mod ? x - mod : x;
}

int sub(int x, int y) {
    x -= y;
    return x < 0 ? x + mod : x;
}

inline int read() {
    int x = 0, f = 0;
    char c = getchar();
    while (!isdigit(c))
        f |= c == '-', c = getchar();
    while (isdigit(c))
        x = x * 10 + c - '0', c = getchar();
    if (f)
        x = -x;
    return x;
}
}  // namespace IO
using namespace IO;

int f[maxn << 1], n;
ll ans;
char s[maxn];
vector<int> e[maxn << 1];

struct SAM {
    int ch[maxn << 1][26], fa[maxn << 1], len[maxn << 1], tot = 1, lst = 1;

    void extend(int x) {
        int p = lst, np = lst = ++tot;
        len[np] = len[p] + 1;
        f[np] = 1;
        for (; p && !ch[p][x]; p = fa[p])
            ch[p][x] = np;
        if (!p)
            fa[np] = 1;
        else {
            int q = ch[p][x];
            if (len[q] == len[p] + 1)
                fa[np] = q;
            else {
                int nq = ++tot;
                memcpy(ch[nq], ch[q], sizeof(ch[q]));
                fa[nq] = fa[q], len[nq] = len[p] + 1;
                fa[q] = fa[np] = nq;
                for (; p && ch[p][x] == q; p = fa[p])
                    ch[p][x] = nq;
            }
        }
    }
} sam;  

void dfs(int x) {
    for (auto v : e[x])
        dfs(v), f[x] += f[v];
    if (f[x] > 1)
        ans = max(ans, 1ll * f[x] * sam.len[x]);
}

signed main() {
    openfile();
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> s + 1;
    n = strlen(s + 1);
    for (int i = 1; i <= n; i++)
        sam.extend(s[i] - 'a');
    for (int i = 1; i <= sam.tot; i++)
        e[sam.fa[i]].push_back(i);
    dfs(1);
    printf("%lld\n", ans);
    cerr << 1.0 * clock() / CLOCKS_PER_SEC << '\n';
    return 0;
}

可持久化 trie

#include <bits/stdc++.h>
using namespace std;

#define int long long
#define pii pair<int, int>
#define mp make_pair
const int maxn = 1e6 + 10;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f3f3f3f3f;

namespace IO {
void openfile() {
#ifndef ONLINE_JUDGE
    freopen("in.in", "r", stdin);
    freopen("out.out", "w", stdout);
#endif
}

int mul(int x, int y) {
    return 1ll * x * y % mod;
}

int add(int x, int y) {
    x += y;

    if (x >= mod)
        x -= mod;

    return x;
}

int sub(int x, int y) {
    return add(x, mod - y);
}

inline int read() {
    int x = 0ll, f = 0ll;
    char c = getchar();

    while (!isdigit(c))
        f |= c == '-', c = getchar();

    while (isdigit(c))
        x = x * 10 + c - '0', c = getchar();

    if (f)
        x = -x;

    return x;
}
}  // namespace IO
using namespace IO;

int n, a[maxn], k;
int sum[maxn];
int ch[maxn << 5][2], tot = 1ll, siz[maxn << 5];
int num[maxn];
priority_queue<pii> q;

void insert(int x) {
    int u = 1ll;

    for (int i = 40ll; i >= 0ll; i--) {
        int op = x >> i & 1ll;

        if (!ch[u][op])
            ch[u][op] = ++tot;

        siz[u]++;
        u = ch[u][op];
    }

    siz[u]++;
}

int k_th(int x, int k) {
    int u = 1ll, ans = 0ll;

    for (int i = 40; i >= 0ll; i--) {
        int op = x >> i & 1ll;

        if (ch[u][op ^ 1ll] && siz[ch[u][op ^ 1ll]] >= k)
            u = ch[u][op ^ 1ll], ans |= 1ll << i;
        else
            k -= siz[ch[u][op ^ 1ll]], u = ch[u][op];
    }

    return ans;
}

signed main() {
    openfile();
    n = read(), k = read();
    k <<= 1ll;

    for (int i = 1ll; i <= n; i++)
        a[i] = read();

    for (int i = 1ll; i <= n; i++)
        sum[i] = sum[i - 1ll] ^ a[i], insert(sum[i]);
    insert(0);

    for (int i = 0ll; i <= n; i++)
        q.push(mp(k_th(sum[i], 1ll), i));

    int ans = 0ll;

    for (int i = 1; i <= k; i++) {
        int x = q.top().first, pos = q.top().second;
        ans += x;
        q.pop();
        num[pos]++;

        if (num[pos] < n)
            q.push(mp(k_th(sum[pos], num[pos] + 1ll), pos));
    }

    printf("%lld\n", ans >> 1);
    return 0ll;
}
posted @ 2025-09-01 22:40  Johnsonloy  阅读(23)  评论(0)    收藏  举报