【border树】【P2375】动物园

Description

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

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

Limitations

1|S|106, 1T5

Solution

好水的NOI题

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

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

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

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

所以只需要在 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, '\n', 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;
}
posted @   一扶苏一  阅读(335)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示