zoukankan      html  css  js  c++  java
  • 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;
    }
    
  • 相关阅读:
    [转]Spring Cloud在国内中小型公司能用起来吗?
    [转]关于maven pom.xml中dependency type 为pom的应用
    如何直接在github网站上更新你fork的repo?
    Eclipse在Tomcat环境下运行项目出现NoClassDefFoundError/ClassNotFoundException解决办法
    Jquery mobile 中在列表项上使用单选按钮
    QBus 关注并推送实时公交信息
    常用序列号
    SVN 使用锁实现独占式签出
    SQL速记
    利用交通在手数据为换乘添加关注
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12523757.html
Copyright © 2011-2022 走看看