[SDOI2016]生成魔咒 后缀自动机

题面:洛谷

题解:

  题意:给定串,对于每个前缀求有多少本质不同的子串。

  我们对这个串建后缀自动机,每加入一个字符就更新一次答案,更新一次输出一次。

  对于后缀自动机上的每个状态,因为以[MINS, MAXS]中的每个值作为长度都可以表示一个不同的子串,所以这个状态的贡献就是这个区间的长度。

  因此建的时候更新ans即可

  

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 #define R register int
 5 #define AC 201000
 6 
 7 LL ans;
 8 struct sam_atm{
 9     int last, cnt;
10     map<int, int> ch[AC];//因为任意一个字符都可能是一个超大的数字,所以要用map
11     int fa[AC], l[AC];
12     
13     inline void add(int c)
14     {
15         int p = last, np = ++ cnt;
16         last = np, l[np] = l[p] + 1;
17         for( ; p && !ch[p][c]; p = fa[p]) ch[p][c] = np;//对于没有这条边的点,加上这条边
18         if(!p) fa[np] = 1, ans += l[np] - l[1];//加上贡献
19         else
20         {
21             int q = ch[p][c];//找到第一个有c这条边的节点的这条边对应的状态
22             if(l[p] + 1 == l[q]) fa[np] = q, ans += l[np] - l[q];//如果不会产生影响,就直接接上去
23             else
24             {
25                 int nq = ++ cnt;//再新建一个节点
26                 l[nq] = l[p] + 1;//长度+1
27                 ch[nq] = ch[q], ans -= l[q] - l[fa[q]];//这是map自带的功能???
28                 //memcpy(ch[nq], ch[q], sizeof(ch[q]));//把对应状态的所有边都赋值到新点上
29                 fa[nq] = fa[q], ans += l[nq] - l[fa[nq]];//把新点连上去,把q拉下来,因为q的位置被改变了,所以要重新统计它的贡献,即删去原来的,加上新的
30                 fa[q] = fa[np] = nq, ans += l[q] + l[np] - (l[nq] << 1);//把这2个点都放在下面
31                 for( ; ch[p][c] == q; p = fa[p]) ch[p][c] = nq;
32             }//因为这里没有涉及fa的改变,所以[Min(s), Max(s)]也没有发生改变,无需修改ans
33         }
34     }
35     
36 }sam;
37 
38 inline int read()
39 {
40     int x = 0;char c = getchar();
41     while(c > '9' || c < '0') c = getchar();
42     while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
43     return x;
44 }
45 
46 void work()
47 {
48     int n = read();
49     sam.last = sam.cnt = 1;//记得初始化!
50     for(R i = 1; i <= n; i ++)
51     {
52         sam.add(read());
53         printf("%lld
", ans);
54     }
55 }
56 
57 int main()
58 {
59 //    freopen("in.in", "r", stdin);
60     work();
61 //    fclose(stdin);
62     return 0;
63 }
View Code

  

原文地址:https://www.cnblogs.com/ww3113306/p/10067575.html