「SDOI2016」生成魔咒

知识点: SAM

原题面 Loj Luogu


题意简述

\(S\) 的所有前缀的本质不同的子串的个数。
\(S\le 10^5, |\sum|\le 10^9\)


分析题意

考察对 SAM 构建过程的理解。

对于一个确定的字符串 \(S\),其本质不同子串的个数,等于所有状态所表示子串的个数之和。
即有下式:

\[ans = \sum_{u\in \operatorname{DAWG}}{\operatorname{len(u)} - \operatorname{len(\operatorname{link}(u))}} \]

对于字符串 \(S\),考虑新加入字符 \(c\) 的影响。
加入 \(c\) 后,显然答案增加 不在 \(S\) 中出现的 \(S+c\) 后缀的个数
设表示 \(S+c\) 的状态为 \(a\),考虑第一个在 \(S\) 中出现的 \(S+c\) 的后缀,会在 SAM 构建中赋值给 \(\operatorname{link}(a)\) 上。
则新字符的贡献即为 \(\operatorname{len}(a) - \operatorname{len}(\operatorname{link}(a))\)

感觉在 SDOI 见了不少模板题了,传统艺能?


代码实现

//知识点:SAM
/*
By:Luckyblock
*/
#include <map>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define ll long long
const int kMaxn = 1e5 + 10;
//=============================================================
int n, last = 1, node_num = 1, link[kMaxn << 1];
std :: map <int, int> ch[kMaxn << 1]; 
ll ans, len[kMaxn << 1];
//=============================================================
inline int read() {
  int f = 1, w = 0; char ch = getchar();
  for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
  for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
  return f * w;
}
void GetMax(int &fir, int sec) {
  if (sec > fir) fir = sec;
}
void GetMin(int &fir, int sec) {
  if (sec < fir) fir = sec;
}
int Insert(int c_) {
  int p = last, now = last = ++ node_num;
  len[now] = len[p] + 1ll;
  for (; p && ! ch[p][c_]; p = link[p]) ch[p][c_] = now;
  if (! p) {link[now] = 1; return now;}
  int q = ch[p][c_];
  if (len[q] == len[p] + 1ll) {link[now] = q; return now;}
  int newq = ++ node_num;
  ch[newq] = ch[q];
  link[newq] = link[q], len[newq] = len[p] + 1ll;
  link[q] = link[now] = newq;
  for (; p && ch[p][c_] == q; p = link[p]) ch[p][c_] = newq;
  return now;
}
//=============================================================
int main() {
  int n = read();
  for (int i = 1; i <= n; ++ i) {
    int x = read(), now = Insert(x);
    printf("%lld\n", ans += (len[now] - len[link[now]]));
  }
  return 0;
}
posted @ 2020-08-17 09:35  Luckyblock  阅读(120)  评论(0编辑  收藏  举报