CF235C Cyclical Quest [后缀自动机]

QAQ

据说是 SAM 的板子。。

题意是求循环同构,并且去重。
循环同构的定义是,aa的循环同构是aa,ab的循环同构是ab,ba

我们很显然,可以往最后面加上第一个字符,做 (length) 次,就好了。

考虑怎么删除,由于 SAM 的不同子串个数是 (sum len_i - len_{fa_i})

其实实际上是 (i) 这个节点包含了 (len_{fa_i}+1) ~ (len_i) 的所有节点,且后缀相同,并且 (fa_i) 对应的字符串是 (i) 的子串,我们删掉这个字符,相当于长度减一。

它是把单链缩成一个点,实际上我们可以抽象的考虑,当他的长度等于 (len_{fa_i}) 时,我们就可以直接跳到 (fa_i) 这个位置,显然,后缀相同,不证明了。

当长度等于 (length) 的时候才计算贡献。

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

int read() {
  int x = 0;
  char c = getchar();
  while (c < 48) c = getchar();
  while (c > 47) x = x * 10 + (c - 48), c = getchar();
  return x;
}

const int maxn = 2e6 + 62;
char s[maxn];
struct SAM {
  int ch[maxn][26], len[maxn], fa[maxn], sz[maxn];
  int las, cnt;
  SAM() { las = cnt = 1; }

  void ins(int c) {
    int p = las, np = las = ++cnt;
    sz[np] = 1, len[np] = len[p] + 1;
    for (; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;
    if (!p) {
      fa[np] = 1;
    } else {
      int q = ch[p][c];
      if (len[q] == len[p] + 1) {
        fa[np] = q;
      } else {
        int nq = ++cnt;
        memcpy(ch[nq], ch[q], sizeof(ch[q]));
        fa[nq] = fa[q], fa[q] = fa[np] = nq, len[nq] = len[p] + 1;
        for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
      }
    }
  }

  vector<int> g[maxn];

  void dfs(int u) {
    for (int v : g[u]) dfs(v), sz[u] += sz[v];
  }
  
  void insert(int len) {
    for (int i = 1; i <= len; i++) ins(s[i] - 'a');
    for (int i = 2; i <= cnt; i++) g[fa[i]].push_back(i);
    dfs(1);
  }

  int vis[maxn];
  void solve(int Len , int qwq) {
    int p = 1, l = 0, ans = 0;
    for (int i = 1; i <= Len; i++) {
      int c = s[i] - 'a';
      while (p && !ch[p][c]) l = len[p = fa[p]];
      if (ch[p][c]) {
        ++l, p = ch[p][c];
      }
    }
    if (l == Len && vis[p] < qwq) {
      vis[p] = qwq, ans += sz[p];
    }
    for (int i = 1; i <= Len; i++) {
      int c = s[i] - 'a';
      while (p && !ch[p][c]) l = len[p = fa[p]];
      if (ch[p][c]) {
        ++l, p = ch[p][c];
      }
      if (l > Len && --l == len[fa[p]]) p = fa[p];
      if (l == Len && vis[p] < qwq) {
        vis[p] = qwq, ans += sz[p];
      }
    }
    printf("%d
", ans);
  }
  
} sam;

signed main() {
  scanf("%s", s + 1);
  sam.insert(strlen(s + 1));
  int _ = read(), qwq = 0;
  while (_--) scanf("%s", s + 1), sam.solve(strlen(s + 1), ++ qwq);
  return 0;
}
原文地址:https://www.cnblogs.com/Isaunoya/p/12523757.html