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 }