• 【border树】【P2375】动物园


    Description

    给定一个字符串 (S),对每个前缀求长度不超过该前缀一半的公共前后缀个数。

    共有 (T) 组数据,每组数据的输出是 (O(1)) 的。

    Limitations

    (1 leq |S| leq 10^6,~1 leq T leq 5)

    Solution

    好水的NOI题

    建出 (border) 树,对于树上每个节点,它的所有 (border) 与它的所有祖先一一对应。这是因为每个节点的父亲是它的最长 (border),数学归纳可以证明这个结论。

    考虑对于这棵 (border) 树上任何一个节点到根的路径上节点的编号一定是单调减小的,这是因为每个结点的最长 (border) 显然小于自身。

    因此,对于一个点 (u),如果 (v) 是一个合法的 (border),那么 (v) 的祖先一定是合法的 (border)。所以合法的 (border) 一定是一条以根为一个端点的链。

    综合上面两条可以得出,如果 (u) 的合法 (border) 对应链的另一个端点为 (v),那么 (u) 的孩子的合法 (border) 的对应端点一定在 (v)(u) 的路径上,因此这个端点位置是单调变深的。

    所以只需要在 dfs 的时候维护根节点到该节点的链,并维护当前节点的答案位置即可。由于答案位置只会变大,因此答案位置的寻找是均摊 (O(1)) 的,暴力往下循环即可。

    总时间复杂度 (O(T |S|))

    Code

    #include <cstdio>
    #include <cstring>
    #include <vector>
    
    const int maxn = 1000006;
    const int MOD = 1000000007;
    
    int T;
    int n, top;
    ll ans;
    char MU[maxn];
    int border[maxn], pos[maxn], stack[maxn];
    std::vector<int>son[maxn];
    
    void KMP();
    void clear();
    int ReadStr(char *p);
    void dfs(const int u);
    
    int main() {
      freopen("1.in", "r", stdin);
      qr(T);
      while (T--) {
        clear();
        n = ReadStr(MU + 1);
        KMP();
        for (int i = 1; i <= n; ++i) {
          son[border[i]].push_back(i);
        }
        dfs(0);
        qw(ans, '
    ', true);
      }
      return 0;
    }
    
    int ReadStr(char *p) {
      auto beg = p;
      do *p = IPT::GetChar(); while ((*p > 'z') || (*p < 'a'));
      do *(++p) = IPT::GetChar(); while ((*p >= 'a') && (*p <= 'z'));
      *p = 0;
      return p - beg;
    }
    
    void KMP() {
      for (int i = 2, j = 0; i <= n; ++i) {
        while (j && (MU[i] != MU[j + 1])) j = border[j];
        if (MU[i] == MU[j + 1]) ++j;
        border[i] = j;
      }
    }
    
    void clear() {
      ans = 1; top = -1;
      for (auto &u : son) {
        u.clear();
      }
      memset(pos, 0, sizeof pos);
    }
    
    void dfs(const int u) {
      stack[++top] = u;
      for (auto v : son[u]) {
        int dv = v >> 1;
        int &_ans = pos[v];
        _ans = pos[u];
        while ((_ans < top) && (stack[_ans + 1] <= dv)) ++_ans;
        dfs(v);
      }
      if (pos[u]) {
        (ans += pos[u] * ans) %= MOD;
      }
      --top;
    }
    
  • 相关阅读:
    关于jQuery中click&live&on中的坑
    redis 主从配置和集群配置
    python 搭建redis集群
    事件冒泡及事件委托的理解(JQuery Dom操作)
    python中import和from-import的区别
    python中赋值-浅拷贝-深拷贝之间的关系
    学生管理系统.JavaScript
    学生管理系统.c
    电梯演讲与原型展示
    软件需求分析
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/11484142.html
Copyright © 2020-2023  润新知