http://acm.hdu.edu.cn/showproblem.php?pid=4691
留个板子。
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 #include <cmath>
6 using namespace std;
7 const int maxn = 1e5+5;
8 int t1[maxn],t2[maxn],c[maxn];//求SA数组需要的中间变量,不需要赋值
9 //待排序的字符串放在s数组中,从s[0]到s[n-1],长度为n,且最大值小于m,
10 //除s[n-1]外的所有s[i]都大于0,r[n-1]=0
11 //函数结束以后结果放在sa数组中
12 bool cmp(int *r,int a,int b,int l)
13 {
14 return r[a] == r[b] && r[a+l] == r[b+l];
15 }
16 void da(int str[],int sa[],int Rank[],int height[],int n,int m)
17 {
18 n++;
19 int i, j, p, *x = t1, *y = t2;
20 //第一轮基数排序,如果s的最大值很大,可改为快速排序
21 for(i = 0;i < m;i++)c[i] = 0;
22 for(i = 0;i < n;i++)c[x[i] = str[i]]++;
23 for(i = 1;i < m;i++)c[i] += c[i-1];
24 for(i = n-1;i >= 0;i--)sa[--c[x[i]]] = i;
25 for(j = 1;j <= n; j <<= 1)
26 {
27 p = 0;
28 //直接利用sa数组排序第二关键字
29 for(i = n-j; i < n; i++)y[p++] = i;//后面的j个数第二关键字为空的最小
30 for(i = 0; i < n; i++)if(sa[i] >= j)y[p++] = sa[i] - j;
31 //这样数组y保存的就是按照第二关键字排序的结果
32 //基数排序第一关键字
33 for(i = 0; i < m; i++)c[i] = 0;
34 for(i = 0; i < n; i++)c[x[y[i]]]++;
35 for(i = 1; i < m;i++)c[i] += c[i-1];
36 for(i = n-1; i >= 0;i--)sa[--c[x[y[i]]]] = y[i];
37 //根据sa和x数组计算新的x数组
38 swap(x,y);
39 p = 1; x[sa[0]] = 0;
40 for(i = 1;i < n;i++)
41 x[sa[i]] = cmp(y,sa[i-1],sa[i],j)?p-1:p++;
42 if(p >= n)break;
43 m = p;//下次基数排序的最大值
44 }
45 int k = 0;
46 n--;
47 for(i = 0;i <= n;i++)Rank[sa[i]] = i;
48 for(i = 0;i < n;i++)
49 {
50 if(k)k--;
51 j = sa[Rank[i]-1];
52 while(str[i+k] == str[j+k])k++;
53 height[Rank[i]] = k;
54 }
55 }
56 int Rank[maxn],height[maxn];
57 int sa[maxn];
58 char s[maxn];
59 int M[maxn][20];
60 int r[maxn];
61 int A[maxn],B[maxn];
62 void RMQ(int n)
63 {
64 for(int i=1;i<=n;i++) M[i][0] = height[i];
65 for(int j=1;(1<<j)<=n;j++)
66 {
67 for(int i=1;(i+(1<<j)-1)<=n;i++)
68 {
69 M[i][j] = min(M[i][j-1],M[i+(1<<(j-1))][j-1]);
70 }
71 }
72 }
73 int ST(int l,int r)
74 {
75 int k = 0;
76 while((1<<(k+1))<=(r-l+1)) k++;
77 return min(M[l][k],M[r-(1<<k)+1][k]);
78 }
79 int lcp(int a,int b)
80 {
81 a = Rank[a],b = Rank[b];
82 if(a>b) swap(a,b);
83 return ST(a+1,b);
84 }
85 int cal(int x)
86 {
87 int res = 0;
88 if(x==0) res++;
89 while(x)
90 {
91 x /= 10;
92 res++;
93 }
94 return res;
95 }
96 int main()
97 {
98 while(scanf("%s",s)!=EOF)
99 {
100 int len = strlen(s);
101 for(int i=0;i<len;i++) r[i] = s[i];
102 r[len] = 0;
103 da(r,sa,Rank,height,len,128);
104 RMQ(len);
105 long long ans1 = 0,ans2 = 0;
106 int T;scanf("%d",&T);
107 for(int i=1;i<=T;i++)
108 {
109 scanf("%d %d",&A[i],&B[i]);
110 if(i==1)
111 {
112 ans1 += B[i]-A[i]+1;
113 ans2 += B[i]-A[i]+3;
114 continue;
115 }
116 int temp = 0;
117 if(A[i]!=A[i-1]) temp = lcp(A[i-1],A[i]);
118 else temp = 1e9;
119 temp = min(temp,B[i]-A[i]);
120 temp = min(temp,B[i-1]-A[i-1]);
121 ans1 += B[i]-A[i]+1;
122 ans2 += B[i]-A[i]-temp+2;
123 ans2 += cal(temp);
124 }
125 printf("%I64d %I64d
",ans1,ans2);
126 }
127 return 0;
128 }