思路见:http://blog.csdn.net/aozil_yang/article/details/77929216。
代码如下:
1 #include <stdio.h> 2 #include <algorithm> 3 #include <string.h> 4 using namespace std; 5 const int N = 1e5 + 100; 6 typedef long long ll; 7 8 /** 9 * sa[i]:表示排在第i位的后缀的起始下标 10 * rank[i]:表示后缀suffix(i)排在第几 11 * height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值 12 * 13 * */ 14 /* 15 如果整数的话模板改成int. 16 加一个数a[n] = 0 。 这样他的排名是第一个。 17 construct(a,n+1); 18 19 字符串的话。 20 len = strlen(str); 21 construct(s,strlen(s)+1); 22 排名第0的是个空字符串。 23 24 height[i]:sa[i-1] 与 sa[i]的LCP(最长公共前缀)值 25 所以height[1] = 0; 26 rank[len] = 0; 27 sa[0] = len; 28 */ 29 int sa[N],rnk[N],height[N]; 30 void construct(const char *s,int n,int m = 256) { 31 static int t1[N],t2[N],c[N]; 32 int *x = t1,*y = t2; 33 int i,j,k,p,l; 34 for (i = 0; i < m; ++ i) c[i] = 0; 35 for (i = 0; i < n; ++ i) c[x[i] = s[i]] ++; 36 for (i = 1; i < m; ++ i) c[i] += c[i - 1]; 37 for (i = n - 1; i >= 0; -- i) sa[--c[x[i]]] = i; 38 for (k = 1; k <= n; k <<= 1) { 39 p = 0; 40 for (i = n - k; i < n; ++ i) y[p++] = i; 41 for (i = 0; i < n; ++ i) if (sa[i] >= k) y[p++] = sa[i] - k; 42 for (i = 0; i < m; ++ i) c[i] = 0; 43 for (i = 0; i < n; ++ i) c[x[y[i]]] ++; 44 for (i = 1; i < m; ++ i) c[i] += c[i - 1]; 45 for (i = n - 1; i >= 0; -- i) sa[--c[x[y[i]]]] = y[i]; 46 std::swap(x,y); 47 p = 1; x[sa[0]] = 0; 48 for (i = 1; i < n; ++ i) 49 x[sa[i]] = y[sa[i - 1]] == y[sa[i]] 50 && y[sa[i - 1] + k] == y[sa[i] + k] ? p - 1: p ++; 51 if (p >= n) break; 52 m = p; 53 } 54 for (i = 0; i < n; ++ i) rnk[sa[i]] = i; 55 for (i = 0,l = 0; i < n; ++ i) { 56 if (rnk[i]) { 57 j = sa[rnk[i] - 1]; 58 while (s[i + l] == s[j + l]) l++; 59 height[rnk[i]] = l; 60 if (l) l--; 61 } 62 } 63 } 64 65 66 int st_min[N][32]; 67 int preLog[N]; 68 int n; 69 void init_rmq() 70 { 71 preLog[1] = 0; 72 for(int i=2;i<=n;i++) 73 { 74 preLog[i] = preLog[i-1]; 75 if((1 << preLog[i] + 1) == i) preLog[i]++; 76 } 77 for(int i=n;i>=1;i--) 78 { 79 st_min[i][0] = height[i]; 80 for(int j=1;(i+(1<<j)-1)<=n;j++) 81 { 82 st_min[i][j] = min(st_min[i][j-1], st_min[i+(1<<j-1)][j-1]); 83 } 84 } 85 } 86 int query_min(int l,int r) 87 { 88 int len = r - l + 1, k = preLog[len]; 89 return min(st_min[l][k], st_min[r-(1<<k)+1][k]); 90 } 91 char s[N]; 92 int lcp(int l, int r) 93 { 94 /*int ql = rnk[l], qr = rnk[r]; 95 if(ql > qr) swap(ql, qr); 96 if(ql == qr) return n - l; 97 return query_min(ql+1, qr);*/ 98 // l and r are number in rnk. 99 if(l == r) return n - sa[l]; 100 return query_min(l+1, r); 101 } 102 103 int main() 104 { 105 int T; scanf("%d",&T); 106 while(T--) 107 { 108 int k; scanf("%d",&k); 109 scanf("%s",s); 110 n = strlen(s); 111 s[n] = 0; 112 construct(s, n+1); 113 init_rmq(); 114 115 ll ans = 0; 116 for(int i=1;i+k-1<=n;i++) 117 { 118 ans += lcp(i, i+k-1); 119 if(i-1 >= 1) ans -= lcp(i-1, i+k-1); 120 if(i+k <= n) ans -= lcp(i, i+k); 121 if(i-1 >= 1 && i+k <= n) ans += lcp(i-1, i+k); 122 } 123 printf("%I64d ",ans); 124 } 125 return 0; 126 }
最后仍然需要注意的是我sa的模板中,除了rnk数组其他都是0-base的。