• CF1276F Asterisk Substrings [后缀自动机]


    抄一下 (color{lack}{n}color{ ed}{antf}) 的题解

    我 nantf 怎么这么强啊…这题我不到半个小时就写掉了…为什么div1的时候只有一个人做掉这个 F 啊…这个不是我 nantf 随随便便就写掉的么…

    这个 CF 评分 3300 的题为什么这么水啊,直接1A了(

    我们先考虑不带 star 的,人人会做,(sum len_i - len_{fa_i})

    考虑 star 在最前面和最后面,最后一个字符插入到 SAM 之前统计一下 (sum len_i - len_{fa_i})

    然后考虑一下空字符和 star 字符,略。

    考虑其他部分的答案,应该是以 (i) 为后缀的数量 ( imes) (i+2) 为前缀的数量,这个挺好做的,下面讲一下。

    我们在 (i) 对应的 (sam) 节点上插入 (i+2) 对应 (rsam) 的节点。

    然后我们知道 (fa_i) 所对应的字符串是 (i) 的后缀,然后在 (sam) 上启发式合并,(rsam) 上面求个链并计算贡献,这题就没了。

    对于我 nantf 来说代码不是特别好写么…所以丢这里好了

    
    int n;
    const int maxn = 4e5 + 54;
    char s[maxn];
    vector<int> g[maxn];
    set<int> Real[maxn];
    int Realsize[maxn], rt[maxn], rev[maxn];
    
    int val[maxn], lg[maxn], dep[maxn];
    
    int getmin(int x, int y) { return dep[x] < dep[y] ? x : y; }
    
    int getpw(int x) { return 1 << x; }
    
    struct mt {
      vector<int> g[maxn];
      int st[maxn][22], idx = 0;
      int dfn[maxn], rev[maxn];
      void dfs(int u) {
        st[dfn[u] = ++idx][0] = u;
        rev[dfn[u]] = u;
        for (int v : g[u]) {
          dfs(v);
          st[++idx][0] = u;
        }
      }
    
      int getlca(int x, int y) {
        if (dfn[x] > dfn[y]) x ^= y ^= x ^= y;
        x = dfn[x], y = dfn[y];
        int t = lg[y - x + 1];
        return getmin(st[x][t], st[y - getpw(t) + 1][t]);
      }
    } qwq;
    
    int getdis(int x, int y) {
      const int lca = qwq.getlca(x, y);
      return dep[x] + dep[y] - 2 * dep[lca];
    }
    
    int ans = 0;
    
    void insert(int v, int u) {
      for (int t : Real[v]) {
        if (Real[u].count(t)) {
          continue;
        } else {
          auto it = Real[u].insert(t).fir;
          auto l = it;
          auto r = it;
          if (l == Real[u].begin())
            l = --Real[u].end();
          else
            --l;
          ++r;
          if (r == Real[u].end()) r = Real[u].begin();
          int a = qwq.rev[*l];
          int b = qwq.rev[*r];
          Realsize[u] += getdis(a, qwq.rev[t]) + getdis(b, qwq.rev[t]) - getdis(a, b);
        }
      }
      Real[v].clear();
      Realsize[v] = 0;
    }
    
    void dfs(int u) {
      for (int v : g[u]) {
        dfs(v);
        if (sz(Real[rt[u]]) < sz(Real[rt[v]])) swap(rt[u], rt[v]);
        insert(rt[v], rt[u]);
      }
      ans += (Realsize[rt[u]] >> 1) * val[u];
    }
    
    struct suffixautomaton {
      int ch[maxn][26];
      int cnt, las;
    
      suffixautomaton() { cnt = las = 1; }
    
      int len[maxn], fa[maxn];
      void ins(int c) {
        int p = las, np = las = ++cnt;
        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;
            len[nq] = len[p] + 1;
            memcpy(ch[nq], ch[q], sizeof(ch[q]));
            fa[nq] = fa[q];
            fa[q] = fa[np] = nq;
            for (; p && ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
          }
        }
      }
    
      void build1() {
        rep(i, 2, cnt) g[fa[i]].pb(i);
        rep(i, 1, cnt) rt[i] = i;
        rep(i, 2, cnt) val[i] = len[i] - len[fa[i]];
        int p = 1;
        rep(i, 1, n - 2) {
          int c = s[i] - 'a';
          p = ch[p][c];
          Real[p].insert(qwq.dfn[rev[i + 2]]);
          Real[p].insert(qwq.dfn[1]);
          Realsize[p] = dep[rev[i + 2]] * 2;
        }
        dfs(1);
      }
    
      void build2() {
        rep(i, 2, cnt) { dep[i] = len[i], qwq.g[fa[i]].pb(i); }
        qwq.dfs(1);
        lg[1] = 0;
        rep(i, 2, maxn - 1) { lg[i] = lg[i >> 1] + 1; }
        rep(j, 1, 20) {
          rep(i, 1, qwq.idx - getpw(j) + 1) qwq.st[i][j] =
              getmin(qwq.st[i][j - 1], qwq.st[i + getpw(j - 1)][j - 1]);
        }
      }
    
      int getcnt() {
        int ans = 0;
        rep(i, 2, cnt) ans += len[i] - len[fa[i]];
        return ans;
      }
    } sam, rsam;
    
    signed main() {
      // code begin.
      in >> (s + 1), n = strlen(s + 1);
      rep(i, 1, n) {
        if (i == n) ans += sam.getcnt();
        sam.ins(s[i] - 'a');
      }
      Rep(i, n, 1) {
        if (i == 1) ans += rsam.getcnt();
        rsam.ins(s[i] - 'a');
        rev[i] = rsam.las;
      }
      ans += sam.getcnt();
      rsam.build2();
      sam.build1();
      ++ans, ++ans;
      out << ans << '
    ';
      return 0;
      // code end.
    }
    
  • 相关阅读:
    websocketpp相关
    大地水准面、大地基准面
    ubuntu18.04 和 qt 5.13.1 安装
    高斯——克吕格投影反算
    高斯——克吕格投影正算
    缓和曲线10麦克康奈尔
    vsCode 需安装的扩展
    显示windows电脑上已连接过的wifi密码
    linux Java项目CPU内存占用高故障排查
    tcpdump常用参数说明及常见操作
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/12654769.html
Copyright © 2020-2023  润新知