zoukankan      html  css  js  c++  java
  • 【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;
    }
    
  • 相关阅读:
    XAF 一对多关系<DC翻译博客二>
    XAF 在BOModel中实现接口<DC翻译博客六>
    XPO – (Gary's post)Stored Procedure Support Coming in V2010 Vol 2 Part1
    XAF 如何从Excel复制多个单元格内容到GridView
    XAF 如何实现对选择的单元格显示矩形框和多单元格的复制及粘贴
    XAF 如何扩展应用程序模型<二> 编辑ListView自动保存
    XAF 模型编辑器
    XAF 用代码扩展和自定义应用程序模型
    XAF 翻译领域构件(DC)技术目录
    XPO (Gary's post)Stored Procedure Support coming in V2010 Vol 2 (Part 2)
  • 原文地址:https://www.cnblogs.com/yifusuyi/p/11484142.html
Copyright © 2011-2022 走看看