洛谷P4070 生成魔咒

题意:给定字符串,求每个前缀的本质不同的子串数量。字符集1e9。

解:在线构造后缀自动机并统计答案。

答案就是∑len[i] - len[fail[i]]

每次增加的时候,至多对三个节点有影响。然而把Q分裂为nQ本质不同的子串数没变。

于是增加的只有len[np] - len[fail[np]]

map维护转移边。

 1 #include <cstdio>
 2 #include <map>
 3 
 4 typedef long long LL;
 5 const int N = 200010;
 6 
 7 int len[N], fail[N], last, top;
 8 LL ans;
 9 std::map<int, int> mp[N];
10 
11 inline void init() {
12     top = last = 1;
13     return;
14 }
15 
16 inline void insert(int f) {
17     int p = last, np = ++top;
18     last = np;
19     len[np] = len[p] + 1;
20     while(p && !mp[p].count(f)) {
21         mp[p][f] = np;
22         p = fail[p];
23     }
24     //printf("p = %d \n", p);
25     if(!p) {
26         fail[np] = 1;
27         ans += len[np];
28         //printf("1 : ans += %d \n", len[np]);
29     }
30     else {
31         int Q = mp[p][f];
32         //printf("Q = %d \n", Q);
33         if(len[Q] == len[p] + 1) {
34             fail[np] = Q;
35             ans += len[np] - len[Q];
36             //printf("2 : ans += %d \n", len[np] - len[Q]);
37         }
38         else {
39             int nQ = ++top;
40             len[nQ] = len[p] + 1;
41             fail[nQ] = fail[Q];
42             fail[Q] = fail[np] = nQ;
43             mp[nQ] = mp[Q];
44             while(mp[p].count(f) && mp[p][f] == Q) {
45                 mp[p][f] = nQ;
46                 p = fail[p];
47             }
48             ans += len[np] - len[nQ];
49         }
50     }
51     return;
52 }
53 
54 int main() {
55     int n;
56     scanf("%d", &n);
57     init();
58     for(int i = 1, x; i <= n; i++) {
59         scanf("%d", &x);
60         insert(x);
61         printf("%lld\n", ans);
62     }
63 
64     return 0;
65 }
AC代码

 

posted @ 2019-01-06 20:31  huyufeifei  阅读(120)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜