集训队论文中有求不同子串个数的做法,就是扫一遍height数组,过程中根据height数组进行去重。对于本题也是雷同的,只是每一次不是根据与排名在上一位的LCP去重,而是与上一次统计对答案有贡献的后缀进行比较去重。
几组数据
abacaba 7
abbacaa 7
baabcaa 5
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <string.h> 6 #include <stdio.h> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <cmath> 12 #include <ctime> 13 #include <cassert> 14 #include <sstream> 15 using namespace std; 16 17 const int N=123456*2; 18 19 char s[N]; 20 struct SuffixArray { 21 int wa[N], wb[N], cnt[N], wv[N]; 22 int rk[N], height[N]; 23 int sa[N]; 24 bool cmp(int r[], int a, int b, int l) { 25 return r[a] == r[b] && r[a+l] == r[b+l]; 26 } 27 void calcSA(char r[], int n, int m) { 28 int i, j, p, *x = wa, *y = wb; 29 for (i = 0; i < m; ++i) cnt[i] = 0; 30 for (i = 0; i < n; ++i) cnt[x[i]=r[i]]++; 31 for (i = 1; i < m; ++i) cnt[i] += cnt[i-1]; 32 for (i = n-1; i >= 0; --i) sa[--cnt[x[i]]] = i; 33 for (j = 1, p = 1; p < n; j *= 2, m = p) { 34 for (p = 0, i = n - j; i < n; ++i) y[p++] = i; 35 for (i = 0; i < n; ++i) if (sa[i] >= j) y[p++] = sa[i] - j; 36 for (i = 0; i < n; ++i) wv[i] = x[y[i]]; 37 for (i = 0; i < m; ++i) cnt[i] = 0; 38 for (i = 0; i < n; ++i) cnt[wv[i]]++; 39 for (i = 1; i < m; ++i) cnt[i] += cnt[i-1]; 40 for (i = n-1; i >= 0; --i) sa[--cnt[wv[i]]] = y[i]; 41 for (swap(x, y), p = 1, x[sa[0]] = 0, i = 1; i < n; ++i) 42 x[sa[i]] = cmp(y, sa[i-1], sa[i], j) ? p-1 : p++; 43 } 44 } 45 void calcHeight(char r[], int n) { 46 int i, j, k = 0; 47 for (i = 0; i <= n; ++i) rk[sa[i]] = i; 48 for (i = 0; i < n; height[rk[i++]] = k) 49 for (k?k--:0, j = sa[rk[i]-1]; r[i+k] == r[j+k]; k++); 50 } 51 int lcp(int a,int b,int len) { 52 if (a==b) return len-a; 53 int ra=rk[a],rb=rk[b]; 54 if (ra>rb) swap(ra,rb); 55 return queryST(ra+1,rb); 56 } 57 int st[N][22]; 58 void initST(int n) { 59 for (int i=1; i<=n; i++) 60 st[i][0]=height[i]; 61 for (int j=1; (1<<j)<=n; j++) { 62 int k=1<<(j-1); 63 for (int i=1; i+k<=n; i++) 64 st[i][j]=min(st[i][j-1],st[i+k][j-1]); 65 } 66 } 67 int queryST(int a,int b) { 68 if (a>b) swap(a,b); 69 int dis=b-a+1; 70 int k=log((double)dis)/log(2.0); 71 return min(st[a][k],st[b-(1<<k)+1][k]); 72 } 73 void solve(int cas) { 74 int n=strlen(s); 75 s[n]='#'; 76 for (int i=0;i<n;i++) { 77 s[n+1+i]=s[n-1-i]; 78 } 79 int o=n; 80 n=2*n+1; 81 s[n]='\0'; 82 calcSA(s,n+1,128); 83 calcHeight(s,n); 84 initST(n); 85 long long ret=0; 86 int curLcp=0; 87 for (int i=1;i<=n;i++) { //odd 88 int pos=sa[i]; 89 curLcp=min(curLcp,height[i]); 90 if (pos<o) { 91 int ops=n-1-pos; 92 int now=lcp(pos,ops,n); 93 ret+=max(0,now-curLcp); 94 if (now>=curLcp) 95 curLcp=now; 96 } 97 } 98 curLcp=0; 99 for (int i=1;i<=n;i++) { //even 100 int pos=sa[i]; 101 curLcp=min(curLcp,height[i]); 102 if (pos<o) { 103 int ops=n-pos; 104 int now=lcp(pos,ops,n); 105 ret+=max(0,now-curLcp); 106 if (now>=curLcp) 107 curLcp=now; 108 } 109 } 110 printf("Case #%d: %I64d\n",cas,ret); 111 } 112 }suf; 113 114 int main () { 115 //freopen("out.txt","r",stdin); 116 int T; 117 scanf("%d",&T); 118 int cas=1; 119 while (T--) { 120 scanf("%s",s); 121 suf.solve(cas); 122 cas++; 123 } 124 return 0; 125 }