題意:求全部後綴兩兩之間的最長公共前綴的長度之和。ide
解:這道題讓我發現了一個奇妙的性質:全部後綴兩兩最長公共前綴長度之和 和 全部前綴兩兩最長公共後綴之和的值是相等的,可是每一組公共前/後綴是不一樣的。spa
由於這道題要反建後綴自動機,我正建而後過了......code
兩個串的最長公共後綴就是在fail樹上的lca。blog
因此反建後綴自動機,全部後綴就是主鏈。而後求這些兩兩的lca計算每一個點做爲lca被統計了多少次,樹上DFS一遍就行了。string
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 5 typedef long long LL; 6 const int N = 1000010; 7 8 struct Edge { 9 int nex, v; 10 }edge[N]; int top; 11 12 int tr[N][26], len[N], fail[N], cnt[N], tot = 1, last = 1; 13 int e[N], siz[N]; 14 LL ans; 15 char s[N]; 16 17 inline void add(int x, int y) { 18 top++; 19 edge[top].v = y; 20 edge[top].nex = e[x]; 21 e[x] = top; 22 return; 23 } 24 25 inline void insert(char c) { 26 int f = c - 'a'; 27 int p = last, np = ++tot; 28 last = np; 29 len[np] = len[p] + 1; 30 cnt[np] = 1; 31 while(p && !tr[p][f]) { 32 tr[p][f] = np; 33 p = fail[p]; 34 } 35 if(!p) { 36 fail[np] = 1; 37 } 38 else { 39 int Q = tr[p][f]; 40 if(len[Q] == len[p] + 1) { 41 fail[np] = Q; 42 } 43 else { 44 int nQ = ++tot; 45 len[nQ] = len[p] + 1; 46 fail[nQ] = fail[Q]; 47 fail[Q] = fail[np] = nQ; 48 memcpy(tr[nQ], tr[Q], sizeof(tr[Q])); 49 while(tr[p][f] == Q) { 50 tr[p][f] = nQ; 51 p = fail[p]; 52 } 53 } 54 } 55 return; 56 } 57 58 inline void prework() { 59 for(int i = 2; i <= tot; i++) { 60 add(fail[i], i); 61 //printf("add : %d %d \n", fail[i], i); 62 } 63 return; 64 } 65 66 void DFS(int x) { 67 siz[x] = cnt[x]; 68 for(int i = e[x]; i; i = edge[i].nex) { 69 int y = edge[i].v; 70 DFS(y); 71 if(x > 1) { 72 ans += 1ll * siz[x] * siz[y] * len[x]; 73 } 74 siz[x] += siz[y]; 75 } 76 //printf("x = %d siz = %d \n", x, siz[x]); 77 return; 78 } 79 80 int main() { 81 LL sum = 0; 82 scanf("%s", s); 83 int n = strlen(s); 84 for(int i = 0; i < n; i++) { 85 insert(s[i]); 86 sum += 1ll * (n - 1) * (i + 1); 87 } 88 prework(); 89 DFS(1); 90 printf("%lld\n", sum - 2 * ans); 91 //printf("%lld - %lld \n", sum, 2 * ans); 92 return 0; 93 }