POJ 1509 后缀数组

链接:

http://poj.org/problem?id=1509

题意:

给你一个环形字符串,问从哪个地方截断使得得到的字符串字典序最小

题解:

计算s+s的后缀数组,然后遍历sa数组,找到第一个小于n的地方 输出即可

但是直接这样做会wa掉,因为有多个结果时,题目要求输出最小的,看了别人的博客知道在后面再加一个char('z'+1)就行了

代码:

31 int n, k;
32 int Rank[MAXN], tmp[MAXN];
33 int sa[MAXN], lcp[MAXN];
34 
35 bool compare_sa(int i, int j) {
36     if (Rank[i] != Rank[j]) return Rank[i] < Rank[j];
37     else {
38         int ri = i + k <= n ? Rank[i + k] : -1;
39         int rj = j + k <= n ? Rank[j + k] : -1;
40         return ri < rj;
41     }
42 }
43 
44 void construct_sa(string S, int *sa) {
45     n = S.length();
46     for (int i = 0; i <= n; i++) {
47         sa[i] = i;
48         Rank[i] = i < n ? S[i] : -1;
49     }
50     for (k = 1; k <= n; k *= 2) {
51         sort(sa, sa + n + 1, compare_sa);
52         tmp[sa[0]] = 0;
53         for (int i = 1; i <= n; i++) 
54             tmp[sa[i]] = tmp[sa[i - 1]] + (compare_sa(sa[i - 1], sa[i]) ? 1 : 0);
55         for (int i = 0; i <= n; i++) Rank[i] = tmp[i];
56     }
57 }
58 
59 void construct_lcp(string S, int *sa, int *lcp) {
60     int n = S.length();
61     for (int i = 0; i <= n; i++) Rank[sa[i]] = i;
62     int h = 0;
63     lcp[0] = 0;
64     for (int i = 0; i < n; i++) {
65         int j = sa[Rank[i] - 1];
66         if (h > 0) h--;
67         for (; j + h < n && i + h < n; h++)
68             if (S[j + h] != S[i + h]) break;
69         lcp[Rank[i] - 1] = h;
70     }
71 }
72 
73 int main() {
74     ios::sync_with_stdio(false), cin.tie(0);
75     int T;
76     cin >> T;
77     while (T--) {
78         string s;
79         cin >> s;
80         s += s + char('z' + 1);
81         construct_sa(s, sa);
82         rep(i, 0, n + 1) if (sa[i] < n / 2) {
83             cout << sa[i] + 1 << endl;
84             break;
85         }
86     }
87     return 0;
88 }

 

posted @ 2017-09-12 14:24  Flowersea  阅读(135)  评论(4编辑  收藏  举报