HDU 4622 Reincarnation

 题目大意:

给定一个基础字符串,再给多个字符串,求出基础字符串中能得到的不一样的子串的个数未出现在后面多个字符串当中

这里以基础子串构建后缀自动机是没问题的

后面的多个子串不断在后缀自动机上进行匹配,每次到达一个状态点,就要更新当前点所能达到的其他字符串抵达最大长度 mx,那么未能匹配的长度就是cur->l-mx

因为父节点受子节点影响,所以要拓扑排序,不断更新父节点所能达到的最大长度,最后统计所有数量之和即可

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4 using namespace std;
 5 
 6 #define N 100010
 7 #define ll long long
 8 struct SamNode{
 9     SamNode *son[26] , *f;
10     int l , mx;
11     void init(){
12         for(int i=0 ; i<26 ; i++) son[i] = NULL;
13         f=NULL;
14         l = mx = 0;
15     }
16 }sam[N<<1] , *root , *last , *b[N<<1];
17 
18 int cnt , num[N];
19 ll ret;
20 char s[N];
21 
22 void add(int x)
23 {
24     SamNode *p = &sam[++cnt] , *jp = last;
25     p->init();
26     p->l = jp->l+1 ;
27     last = p;
28     for( ; jp&&!jp->son[x] ; jp=jp->f) jp->son[x] = p;
29     if(!jp) p->f = root;
30     else{
31         if(jp->l+1 == jp->son[x]->l) p->f = jp->son[x];
32         else{
33             SamNode *r = &sam[++cnt] , *q = jp->son[x];
34             r->init();
35             *r = *q;
36             r->l = jp->l+1;
37             p->f = q->f = r;
38             for( ; jp&&jp->son[x]==q ; jp=jp->f) jp->son[x]=r;
39         }
40     }
41 }
42 
43 void solve(int n , int &cas)
44 {
45     int l , len=strlen(s);
46     memset(num , 0 , sizeof(num));
47     for(int i=0 ; i<=cnt ; i++) num[sam[i].l]++;
48     for(int i=1 ; i<=len ; i++) num[i]+=num[i-1];
49     for(int i=0 ; i<=cnt ; i++) b[--num[sam[i].l]]=&sam[i];
50     for(int i=0 ; i<n ; i++){
51         scanf("%s" , s);
52         l=strlen(s) , len=0; //len表示当前所能达到的最大长度
53         SamNode *cur = root;
54         for(int j=0 ; j<l ; j++){
55             int x = s[j]-'a';
56             if(cur->son[x]){
57                 len++;
58                 cur = cur->son[x];
59                 cur->mx = max(cur->mx , len);
60             }else{
61                 while(cur&&!cur->son[x]) cur=cur->f;
62                 if(!cur)
63                     cur = root , len=0;
64                 else{
65                     len = cur->l+1;
66                     cur = cur->son[x];
67                     cur->mx = max(cur->mx , len);
68                 }
69             }
70         }
71     }
72     ll ret = 0;
73     for(int i=cnt ; i>=1 ; i--){
74        // cout<<i<<" "<<b[i]->l<<" "<<b[i]->mx<<endl;
75         if(b[i]->mx) ret = ret + (b[i]->l-b[i]->mx>=0?b[i]->l-b[i]->mx:0);
76         else ret = ret + b[i]->l-b[i]->f->l;
77         b[i]->f->mx = max(b[i]->f->mx , b[i]->mx);
78     }
79     printf("Case %d: %I64d
" , ++cas , ret);
80 }
81 
82 int main()
83 {
84    // freopen("a.in" , "r", stdin);
85     int T , n , cas=0;
86     scanf("%d" , &T);
87     while(T--)
88     {
89         scanf("%d%s" , &n , s);
90         int l = strlen(s);
91         sam[0].init();
92         root = last = &sam[cnt=0] , ret = 0;
93         for(int i=0 ; i<l ; i++)
94             add(s[i]-'a');
95         solve(n , cas);
96     }
97     return 0;
98 }
原文地址:https://www.cnblogs.com/CSU3901130321/p/4596697.html