BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

http://www.lydsy.com/JudgeOnline/problem.php?id=3238

就算是全局变量,也不要忘记,初始化(吐血)。

长得一副lca样,没想到是个树形dp(小丫头还有两幅面孔呢)。

看代码实现吧,不大容易口头解释,把加的和减的分开算就可以了,减去的通过倒着建sam(相当于建一棵后缀树),然后算每个len取的次数实现,注意树归中一些避免重复操作。

 1 /**************************************************************
 2     Problem: 3238
 3     User: 137shoebills
 4     Language: C++
 5     Result: Accepted
 6     Time:3816 ms
 7     Memory:130688 kb
 8 ****************************************************************/
 9  
10 #include<iostream>
11 #include<cstdio>
12 #include<algorithm>
13 #include<cstring>
14 #include<cmath>
15 #include<map>
16 using namespace std;
17 const int maxn=500010;
18 char ch1[maxn]={};
19 int siz;
20 struct nod{
21     int sig[26];
22     int f,len;
23 }t[maxn*2];int tot=1,la=1;
24 void add(int z){
25     int x=++tot;int i=la;
26     t[x].len=t[la].len+1;
27     for(;i&&!t[i].sig[z];i=t[i].f)
28         t[i].sig[z]=x;
29     if(!i)t[x].f=1;
30     else{
31         int p=t[i].sig[z];
32         if(t[p].len==t[i].len+1)t[x].f=p;
33         else{
34             int y=++tot;
35             t[y]=t[p];t[y].len=t[i].len+1;
36             t[x].f=t[p].f=y;
37             for(;i&&t[i].sig[z]==p;i=t[i].f)
38                 t[i].sig[z]=y;
39         }
40     }
41     la=x;
42 }
43 struct node{
44     int y,next;
45 }e[maxn*2];int cnt=0;
46 int head[maxn*2]={};
47 long long dp[maxn*2]={},sum=0;
48 void init(int x,int y){e[++cnt].y=y;e[cnt].next=head[x];head[x]=cnt;}
49 void dfs(int x){
50     int y;
51     long long num=dp[x]*dp[x];
52     for(int i=head[x];i;i=e[i].next){
53         y=e[i].y;
54         dfs(y);dp[x]+=dp[y];
55         num+=dp[y]*dp[y];
56     }
57     sum+=(dp[x]*dp[x]-num)*t[x].len;
58 }
59 long long solve(){
60     int j=1;
61     for(int i=siz;i>=1;i--){
62         j=t[j].sig[ch1[i]-'a'];
63         dp[j]++;
64     }
65     for(int i=2;i<=tot;i++)
66         init(t[i].f,i);
67     dfs(1);
68     return sum;
69 }
70 int main(){
71     memset(t,0,sizeof(t));
72     scanf("%s",ch1+1);siz=strlen(ch1+1);
73     for(int i=siz;i>=1;i--)add((int)(ch1[i]-'a'));
74     long long ans=0;
75     for(int i=1;i<=siz;i++)ans+=(long long)i*(siz-1);
76     printf("%lld\n",ans-solve());
77     return 0;
78 }
View Code

 

posted @ 2018-03-14 21:07  鲸头鹳  阅读(154)  评论(0编辑  收藏  举报