思路见: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\n",ans);
124     }
125     return 0;
126 }

  

  最后仍然需要注意的是我sa的模板中,除了rnk数组其他都是0-base的。