看了一上午看明白了后缀数组的DA构造方法,自己模拟写了一个,发现了一点问题
我的模板
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include <iostream>
2 #include <cstdio>
3 #include <algorithm>
4 #include <cstring>
5 using namespace std;
6 const int MAXN = 210000;
7 struct Sfx
8 {
9 int i;
10 int key[2];
11 bool operator < (const Sfx& s) const
12 {
13 if(key[0] == s.key[0])
14 return key[1] < s.key[1];
15 return key[0] < s.key[0] ;
16 }
17 } sfxArray[MAXN], temp[MAXN];
18 int rank[MAXN], bucket[MAXN], height[MAXN];// rank from 0 to n - 1
19 //基数排序,先拍第二关键字,再第一关键字
20 void radixSort(Sfx* in, int n, int idx, Sfx* out)
21 {
22 memset(bucket, 0, sizeof(int) * (n + 1));
23 for (int i = 0; i < n; i++)
24 bucket[in[i].key[idx]]++;
25 for (int i = 1; i <= n; i++)
26 bucket[i] += bucket[i - 1];
27 for (int i = n - 1; i >= 0; i--)//for down
28 out[--bucket[in[i].key[idx]]] = in[i];
29 }
30 void buildSA(char* text, int n)
31 {
32 for (int i = 0; i < n; i++)
33 {
34 sfxArray[i].i = sfxArray[i].key[1] = i;
35 sfxArray[i].key[0] = text[i];
36 }
37 sort(sfxArray, sfxArray + n);
38 //radixSort(sfxArray, n, 1, temp);
39 //radixSort(sfxArray, n, 0, temp);
40 for (int i = 0; i < n; i++)//下面要比较,所以全变为0
41 sfxArray[i].key[1] = 0;
42 int wid = 1;
43 while (wid < n)
44 {
45 rank[sfxArray[0].i] = 0;
46 for (int i = 1; i < n; i++)
47 rank[sfxArray[i].i] = rank[sfxArray[i - 1].i] + (sfxArray[i - 1] < sfxArray[i]);
48 for (int i = 0; i < n; i++)
49 {
50 sfxArray[i].i = i;
51 sfxArray[i].key[0] = rank[i];
52 sfxArray[i].key[1] = i + wid < n ? rank[i + wid]: 0;
53 }
54 radixSort(sfxArray, n, 1, temp);
55 radixSort(temp, n, 0, sfxArray);
56 wid <<= 1;
57 }
58 }
59 void calHeight(char* text, int* rank, int n)
60 {//h[i] = height[rank[i]], h[i] >= h[i - 1] - 1;
61 for(int i = 0;i < n;i++)
62 rank[sfxArray[i].i] = i;
63 for(int i = 0, k = 0, j; i < n; i++)
64 {
65 if (rank[i] == 0)
66 height[rank[i]] = 0;
67 else
68 {
69 if(k > 0) k-- ;
70 for (j = sfxArray[rank[i] - 1].i; text[i + k] == text[j + k];k++);//+1 -1
71 height[rank[i]] = k;
72 }
73 }
74 }
75 char str1[MAXN], str2[MAXN];
76 int main()
77 {
78 scanf("%s %s", str1, str2);
79 int len1 = strlen(str1);
80 int len2 = strlen(str2);
81 int n = len1 + len2 + 1;
82 str1[len1] = '$', str1[len1 + 1] = 0;
83 strcat(str1, str2);
84 buildSA(str1, n);
85 calHeight(str1, rank, n);
86 int ans = 0;
87 for(int i = 1;i < n;i++)
88 {
89 if((sfxArray[i].i < len1 && sfxArray[i - 1].i > len1) ||
90 (sfxArray[i].i > len1 && sfxArray[i - 1].i < len1))
91 ans = max(ans, height[i]);
92 }
93 printf("%d\n", ans);
94 return 0;
95 }
膜拜注释的地方我感觉用radixSort代替sort是完全可以的,但是却不行,请过路过的大牛指点一下。
这题还有一个trick就是最后的h[i]一定要保证 sa[i].i 和sa[i - 1].i 不在同一个字符串里,纠结了很长时间google一下别人的代码……鄙视自己。
有时间详细写一下我对后缀数组的理解吧,抓紧多做几道题先!
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /*
2 * =====================================================================================
3 *
4 * Filename: DA.cpp
5 *
6 * Description:
7 *
8 * Version: 1.0
9 * Created: 2011/7/20 19:26:09
10 * Revision: none
11 * Compiler: gcc
12 *
13 * Author: ronaflx
14 * Company: hit-acm-group
15 *
16 * =====================================================================================
17 */
18 #include <iostream>
19 #include <cstdio>
20 #include <cstring>
21 #include <cstdlib>
22 #include <algorithm>
23 #include <numeric>
24 #include <iterator>
25 using namespace std;
26 const int MAXN = 210000;
27
28 struct Sfx
29 {
30 int i;
31 int key[2];
32 bool operator < (const Sfx& s) const
33 {
34 if(key[0] == s.key[0])
35 return key[1] < s.key[1];
36 return key[0] < s.key[0] ;
37 }
38 } sfxArray[MAXN], temp[MAXN];
39 int rank[MAXN], bucket[MAXN], height[MAXN], h[MAXN];// rank from 0 to n - 1
40 //基数排序,先拍第二关键字,再第一关键字
41 void radixSort(Sfx* in, int n, int idx, Sfx* out)
42 {
43 memset(bucket, 0, sizeof(int) * (n + 1));
44 for (int i = 0; i < n; i++)
45 bucket[in[i].key[idx]]++;
46 for (int i = 1; i <= n; i++)
47 bucket[i] += bucket[i - 1];
48 for (int i = n - 1; i >= 0; i--)//for down
49 out[--bucket[in[i].key[idx]]] = in[i];
50 }
51 void buildSA(int* text, int n)
52 {
53 for (int i = 0; i < n; i++)
54 {
55 sfxArray[i].i = sfxArray[i].key[1] = i;
56 sfxArray[i].key[0] = text[i];
57 }
58 sort(sfxArray, sfxArray + n);
59 for (int i = 0; i < n; i++)//下面要比较,所以全变为0
60 sfxArray[i].key[1] = 0;
61 int wid = 1;
62 while (wid < n)
63 {
64 rank[sfxArray[0].i] = 0;
65 for (int i = 1; i < n; i++)
66 rank[sfxArray[i].i] = rank[sfxArray[i - 1].i] + (sfxArray[i - 1] < sfxArray[i]);
67 for (int i = 0; i < n; i++)
68 {
69 sfxArray[i].i = i;
70 sfxArray[i].key[0] = rank[i];
71 sfxArray[i].key[1] = i + wid < n ? rank[i + wid]: 0;
72 }
73 radixSort(sfxArray, n, 1, temp);
74 radixSort(temp, n, 0, sfxArray);
75 wid <<= 1;
76 }
77 }
78 void calHeight(int* text, int* rank, int n)
79 {//h[i] = height[rank[i]], h[i] >= h[i - 1] - 1;
80 for(int i = 0;i < n;i++)
81 rank[sfxArray[i].i] = i;
82 for(int i = 0, k = 0, j; i < n; i++)
83 {
84 if (rank[i] == 0)
85 height[rank[i]] = 0;
86 else
87 {
88 if(k > 0) k-- ;
89 for (j = sfxArray[rank[i] - 1].i; text[i + k] == text[j + k];k++);
90 height[rank[i]] = k;
91 }
92 }
93 }
94
95 int num[MAXN], tmp[MAXN];
96
97
98 bool judge(int n, int k)
99 {
100 int minn = sfxArray[0].i, maxn = sfxArray[0].i;
101 for(int i = 1;i < n;i++)
102 {
103 if(height[i] < k) minn = maxn = sfxArray[i].i;
104 else
105 {
106 minn = min(minn, sfxArray[i].i);
107 maxn = max(maxn, sfxArray[i].i);
108 }
109 if(maxn - minn > k) return true;
110 }
111 return false;
112 }
113
114
115 int binary_search(int low, int high, int n)
116 {
117 int reach = 0;
118 while(low <= high)
119 {
120 int mid = (low + high) / 2;
121 if(judge(n, mid))
122 {
123 reach = mid;
124 low = mid + 1;
125 }
126 else high = mid - 1;
127 }
128 return reach;
129 }
130 int main()
131 {
132 int n;
133 while(scanf("%d", &n) == 1 && n)
134 {
135 for(int i = 0;i < n;i++)
136 scanf("%d", &num[i]);
137 adjacent_difference(num, num + n, tmp);
138 transform(tmp, tmp + n, num, bind2nd(minus<int>(), *min_element(tmp, tmp + n) - 1));
139 num[n] = 0;
140 buildSA(num, n);
141 calHeight(num, rank, n);
142 int ans = binary_search(1, n / 2, n) + 1;
143 printf("%d\n", ans >= 5 ? ans : 0);
144 }
145 return 0;
146 }
PS.此题网上的大多数程序貌似都有问题,如下数据
11
1 2 3 4 5 6 7 8 9 10 11
答案是5
具体的算法参考09罗某后缀数组论文中的分析,后缀数组height的性质NB呀!!无限仰慕此数据结构。接下来的任务是继续学习后缀数组。然后复习图论网络流以及DP,开学前再看几何!
07.27更新
最长回文串
![ContractedBlock.gif](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![ExpandedBlockStart.gif](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 /*
2 * =====================================================================================
3 *
4 * Filename: suffixArray.cpp
5 *
6 * Description:
7 *
8 * Version: 1.0
9 * Created: 2011年07月27日 13时31分08秒
10 * Revision: none
11 * Compiler: gcc
12 *
13 * Author: ronaflx
14 * Company: hit-ACM-Group
15 *
16 * =====================================================================================
17 */
18
19 #include <cstdlib>
20 #include <cctype>
21 #include <cstring>
22 #include <cstdio>
23 #include <cmath>
24 #include <ctime>
25 #include <climits>
26 #include <algorithm>
27 #include <functional>
28 #include <numeric>
29 #include <vector>
30 #include <map>
31 #include <set>
32 #include <queue>
33 #include <stack>
34 #include <bitset>
35 #include <list>
36 #include <string>
37 #include <iostream>
38 #include <sstream>
39 #include <fstream>
40 #include <iomanip>
41 #include <stdexcept>
42 #include <utility>
43 #include <cassert>
44 #include <complex>
45 using namespace std;
46 #define LEFT(i) ((i) << 1)
47 #define RIGHT(i) (((i) << 1) | 1)
48 #define MID(i) ((l[i] + r[i]) >> 1)
49 #define CC(i, v) memset(i, v, sizeof(i))
50 #define REP(i, l, n) for(int i = l;i < int(n);++i)
51 #define FOREACH(con, i) for(__typeof(con.begin()) i = con.begin();i != con.end();++i)
52 const int MAXN = 21000;
53
54 struct Sfx
55 {
56 int i;
57 int key[2];
58 bool operator < (const Sfx& s) const
59 {
60 if(key[0] == s.key[0])
61 return key[1] < s.key[1];
62 return key[0] < s.key[0] ;
63 }
64 } sfxArray[MAXN], temp[MAXN];
65 int __rank[MAXN], bucket[MAXN], height[MAXN], h[MAXN];// __rank from 0 to n - 1
66 //基数排序,先拍第二关键字,再第一关键字
67 void radixSort(Sfx* in, int n, int idx, Sfx* out)
68 {
69 memset(bucket, 0, sizeof(int) * (n + 1));
70 for (int i = 0; i < n; i++)
71 bucket[in[i].key[idx]]++;
72 for (int i = 1; i <= n; i++)
73 bucket[i] += bucket[i - 1];
74 for (int i = n - 1; i >= 0; i--)//for down
75 out[--bucket[in[i].key[idx]]] = in[i];
76 }
77 void buildSA(const char* text, int n)
78 {
79 for (int i = 0; i < n; i++)
80 {
81 sfxArray[i].i = sfxArray[i].key[1] = i;
82 sfxArray[i].key[0] = text[i];
83 }
84 sort(sfxArray, sfxArray + n);
85 for (int i = 0; i < n; i++)//下面要比较,所以全变为0
86 sfxArray[i].key[1] = 0;
87 int wid = 1;
88 while (wid < n)
89 {
90 __rank[sfxArray[0].i] = 0;
91 for (int i = 1; i < n; i++)
92 __rank[sfxArray[i].i] = __rank[sfxArray[i - 1].i] + (sfxArray[i - 1] < sfxArray[i]);
93 for (int i = 0; i < n; i++)
94 {
95 sfxArray[i].i = i;
96 sfxArray[i].key[0] = __rank[i];
97 sfxArray[i].key[1] = i + wid < n ? __rank[i + wid]: 0;
98 }
99 radixSort(sfxArray, n, 1, temp);
100 radixSort(temp, n, 0, sfxArray);
101 wid <<= 1;
102 }
103 }
104 void calHeight(const char* text, int* __rank, int n)
105 {//h[i] = height[__rank[i]], h[i] >= h[i - 1] - 1;
106 for(int i = 0;i < n;i++)
107 __rank[sfxArray[i].i] = i;
108 for(int i = 0, k = 0, j; i < n; i++)
109 {
110 if (__rank[i] == 0)
111 height[__rank[i]] = 0;
112 else
113 {
114 if(k > 0) k-- ;
115 for (j = sfxArray[__rank[i] - 1].i; text[i + k] == text[j + k];k++);
116 height[__rank[i]] = k;
117 }
118 }
119 }
120 int RMQ[MAXN][20];
121 void buildRMQ(int n, int* height)
122 {
123 for(int i = 1;i <= n;i++) RMQ[i][0] = height[i - 1];
124 for (int j = 1; j <= log(n + 0.00) / log(2.0); j++)
125 for (int i = 1; i + (1 << j) - 1 <= n; i++)
126 RMQ[i][j] = min(RMQ[i][j - 1], RMQ[i + (1 << (j - 1))][j - 1]);
127 }
128 int queryRMQ(int a, int b)
129 {
130 int len = log(b - a + 1.0) / log(2.0);
131 return min(RMQ[a][len], RMQ[b - (1 << len) + 1][len]);
132 }
133 int queryLCP(int a, int b)
134 {
135 a = __rank[a] + 1;
136 b = __rank[b] + 1;
137 if(a > b) swap(a, b);
138 return queryRMQ(a + 1, b);
139 }
140 int main()
141 {
142 string str;
143 while(cin >> str)
144 {
145 int n = str.size(), m = str.size();
146 string tmp = str;
147 reverse(tmp.begin(), tmp.end());
148 str = str + '#' + tmp;
149 n = (n << 1) + 1;
150 buildSA(str.data(), n);
151 calHeight(str.data(), __rank, n);
152 buildRMQ(n, height);
153 int ans = 0, idx;
154 for(int i = 0;i < m;i++)
155 {
156 int j = queryLCP(i, n - i);
157 if(i > 0 && j * 2 > ans)//偶数回文
158 ans = j * 2, idx = i - j;
159 j = queryLCP(i, n - i - 1);
160 if(j * 2 - 1 > ans)//奇数回文
161 ans = j * 2 - 1, idx = i - j + 1;
162 }
163 reverse(tmp.begin(), tmp.end());
164 printf("%s\n", tmp.substr(idx, ans).data());
165 }
166 return 0;
167 }