bzoj 3238

 

建出后缀自动机,考虑每条边的贡献。

 

发现后缀自动机的val和right集合大小都可以在转移DAG上DP(需要记录每个终止位置所在节点)。

 

 1 /**************************************************************
 2     Problem: 3238
 3     User: idy002
 4     Language: C++
 5     Result: Accepted
 6     Time:2444 ms
 7     Memory:122388 kb
 8 ****************************************************************/
 9  
10 #include <cstdio>
11 #include <cstring>
12 #define N 500010
13 #define S N<<1
14  
15 typedef long long dnt;
16  
17 int n;
18 int son[S][26], pnt[S], val[S], rsz[S], ntot, last;
19 int idgr[S], qu[S], bg, ed;
20 char buf[N];
21 dnt ans;
22  
23 void init() {
24     pnt[0] = -1;
25 }
26 void append( int c ) {
27     int p = last;
28     int np = ++ntot;
29     val[np] = val[p]+1;
30     while( p!=-1 && !son[p][c] )
31         son[p][c]=np, p=pnt[p];
32     if( p==-1 ) {
33         pnt[np] = 0;
34     } else {
35         int q=son[p][c];
36         if( val[q]==val[p]+1 ) {
37             pnt[np] = q;
38         } else {
39             int nq = ++ntot;
40             memcpy( son[nq], son[q], sizeof(son[nq]) );
41             val[nq] = val[p]+1;
42             pnt[nq] = pnt[q];
43             pnt[q] = pnt[np] = nq;
44             while( p!=-1 && son[p][c]==q )
45                 son[p][c]=nq, p=pnt[p];
46         }
47     }
48     last = np;
49     rsz[np] = 1;
50 }
51 void make_topo() {
52     bg=1, ed=0;
53     for( int u=1; u<=ntot; u++ )
54         idgr[pnt[u]]++;
55     for( int u=0; u<=ntot; u++ )
56         if( idgr[u]==0 && u ) qu[++ed]=u;
57     while( bg<=ed ) {
58         int u=qu[bg++];
59         idgr[pnt[u]]--;
60         if( idgr[pnt[u]]==0 && pnt[u] )
61             qu[++ed] = pnt[u];
62     }
63 }
64 int main() {
65     scanf( "%s", buf );
66     n = strlen(buf);
67     init();
68     for( int i=0; buf[i]; i++ )
69         append( buf[i]-'a' );
70     make_topo();
71     for( int i=1; i<=ed; i++ ) {
72         int u=qu[i];
73         rsz[pnt[u]] += rsz[u];
74     }
75     dnt ans = 0;
76     for( int u=1; u<=ntot; u++ ) 
77         ans += ((dnt)rsz[u]*(rsz[u]-1)*(val[u]-val[pnt[u]]));
78     ans = -ans;
79     for( int i=1; i<=n; i++ )
80         ans += (dnt)i*(n-i)+((dnt)(n-i)*(i+n+1)>>1);
81     printf( "%lld\n", ans );
82 }
View Code

 

posted @ 2015-05-20 21:36  idy002  阅读(188)  评论(0编辑  收藏  举报