【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

 

3238: [Ahoi2013]差异

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 3047  Solved: 1375

Description

Input

一行,一个字符串S

Output

 

一行,一个整数,表示所求值

Sample Input

cacao

Sample Output


54

HINT

 



2<=N<=500000,S由小写英文字母组成

 

Source

 

【分析】

  这题先把sigma len 加上。

  然后考虑一下减掉的是什么。

  对于每个子串,假设出现次数是x,那么对答案的贡献就是x*(x-1)/2*2即ans-=x*(x-1)。

  这个用SAM对每个点的right进行计算即可。

  当然也可以用后缀数组。【后缀数组要用单调栈吧?套路啊。。

 

 1 #include<cstdio>
 2 #include<cstdlib>
 3 #include<cstring>
 4 #include<iostream>
 5 #include<algorithm>
 6 using namespace std;
 7 #define Maxn 500010
 8 #define LL long long
 9 
10 struct node
11 {
12     int son[30],pre,step,rt;
13     // node() {rt=0;}
14 }t[Maxn*2];
15 int v[Maxn*2],q[Maxn*2];
16 
17 struct sam
18 {
19     int last,tot;
20     void extend(int k)
21     {
22         int np=++tot,p=last;
23         t[np].step=t[p].step+1;
24         t[np].rt=1;
25         while(p&&!t[p].son[k])
26         {
27             t[p].son[k]=np;
28             p=t[p].pre;
29         }
30         if(!p) t[np].pre=1;
31         else
32         {
33             int q=t[p].son[k];
34             if(t[q].step==t[p].step+1) t[np].pre=q;
35             else
36             {
37                 int nq=++tot;
38                 memcpy(t[nq].son,t[q].son,sizeof(t[nq].son));
39                 t[nq].step=t[p].step+1;
40                 t[nq].pre=t[q].pre;
41                 t[q].pre=t[np].pre=nq;
42                 while(p&&t[p].son[k]==q)
43                 {
44                     t[p].son[k]=nq;
45                     p=t[p].pre;
46                 }
47             }
48         }
49         last=np;
50     }
51     void init()
52     {
53         memset(v,0,sizeof(v));
54         for(int i=1;i<=tot;i++) v[t[i].step]++;
55         for(int i=1;i<=tot;i++) v[i]+=v[i-1];
56         for(int i=tot;i>=1;i--) q[v[t[i].step]--]=i;
57         
58         for(int i=tot;i>=1;i--)
59         {
60             int nw=q[i];
61             t[t[nw].pre].rt+=t[nw].rt;
62         }
63     }
64 }sam;
65 
66 char s[Maxn];
67 
68 int main()
69 {
70     LL ans=0;
71     scanf("%s",s);
72     int l=strlen(s);
73     sam.last=sam.tot=1;
74     for(int i=0;i<l;i++) sam.extend(s[i]-'a'+1);
75     ans=1LL*l*(l+1)*(l-1)/2;
76     sam.init();t[1].step=0;
77     for(int i=2;i<=sam.tot;i++)
78     {
79         ans-=1LL*(t[i].step-t[t[i].pre].step)*t[i].rt*(t[i].rt-1);
80     }
81     printf("%lld\n",ans);
82     return 0;
83 }
View Code

 

2017-04-17 21:06:17

posted @ 2017-04-17 21:06  konjak魔芋  阅读(271)  评论(0编辑  收藏  举报