http://poj.org/problem?id=3581
1.第一段是显然的,reverse原数组然后求后缀数组取sa[0]即可……当然要注意每段不能为空这个特点
2.在求第二段的时候就会遇到这道题的难点,如果单纯求后缀数组取sa[0],很容易举出反例
7
10 0 2 2 2 2 3
或者
8
10 0 3 1 2 3 1 5
后缀数组在比较大小的时候 是默认"2" 比 "222"小的,但是当其后面还要接其它字符串的时候,相对大小就发生了改变。
有string a,b,c;
a < b 推导不出 a+c < b+c Terrible!
3.看到Discuss里有人说用最小表示法能做,我表示已经忘记最小表示法怎么写了,觉得那东西很难派上用场也懒得再学……但是思考:用后缀数组怎么求解最小表示?
解决方法:取b = a+a; b的前a.size()个后缀中最小的那个后缀的前a.size()位
//如果要求高一些,像"bababa"这样有循环节的字符串要求起始下标最小的最小表示。假设你找到的最小的那个后缀是sa[i] 那要输出的结果就是与它LCP >= a.size()的最后一个(sa数组中)。下面这份代码需要改一些小细节才能实现这个功能,具体见下一篇博客。
4.回过头来求第二段,方法和上面的几乎是一样的,只是先把a取个反而已
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <algorithm>
#include <stack>
#include <cctype>
#include <cmath>
#include <vector>
#include <sstream>
#include <bitset>
#include <deque>
#include <iomanip>
using namespace std;
#define pr(x) cout << #x << " = " << x << endl;
#define bug cout << "bugbug" << endl;
#define ppr(x, y) printf("(%d, %d)\n", x, y);
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define SQR(a) ((a)*(a))
#define PCUT puts("\n---------------")
typedef long long ll;
typedef double DBL;
typedef pair<int, int> P;
typedef unsigned int uint;
const int MOD = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn = 4e5 + 4;
const int maxm = 1e3 + 4;
const double pi = acos(-1.0);
int a[maxn], b[maxn];
vector<int> v;
int Getid(int num){
return lower_bound(v.begin(), v.end(), num) - v.begin();
}
struct SuffixArray{
int n, t[maxn << 1], t2[maxn << 1], c[maxn], sa[maxn], Rank[maxn], Height[maxn];
int s[maxn];
void build_sa(int m){
memset(t, 0, sizeof t);
memset(t2, 0, sizeof t2);
int i, *x = t, *y = t2;
for (i = 0; i < m; ++i) c[i] = 0;
for (i = 0; i < n; ++i) c[x[i] = s[i]]++;
for (i = 1; i < m; ++i) c[i] += c[i-1];
for (i = n-1; i >= 0; --i) sa[--c[x[i]]] = i;
for (int k = 1; k < n; k *= 2){
int p = 0;
for (i = n - k; i < n; ++i) y[p++] = i;
for (i = 0; i < n; ++i)
if (sa[i] >= k) y[p++] = sa[i] - k;
for (i = 0; i < m; ++i) c[i] = 0;
for (i = 0; i < n; ++i) c[x[y[i]]]++;
for (i = 1; i < m; ++i) c[i] += c[i-1];
for (i = n-1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
swap(x, y);
p = 1; x[sa[0]] = 0;
for (i = 1; i < n; ++i)
x[sa[i]] = y[sa[i]] == y[sa[i-1]] && y[sa[i-1] + k] == y[sa[i] + k] ? p-1 : p++;
if (p >= n) break;
m = p;
}
return;
}
void RankAndHeight(){
for (int i = 0; i < n; ++i) Rank[sa[i]] = i;
int k = 0;
Height[sa[0]] = 0;
for (int i = 1; i < n; ++i){
if (k) k--;
if (Rank[i] == 0) continue;
int *p = s + i, *q = s + sa[Rank[i]-1];
while(p[k] == q[k]) k++;
Height[i] = k;
}
return;
}
}SA;
int main(){
//必须编译过才能交
int ik, i, j, k, kase;
int n;
scanf("%d", &n);
for (i = 0; i < n; ++i) scanf("%d", a+i), v.push_back(a[i]);
sort(v.begin(), v.end());
unique(v.begin(), v.end());
for (i = 0; i < n; ++i) a[i] = Getid(a[i]);
reverse(a, a+n-2);
memcpy(SA.s, a, sizeof a);
SA.n = n - 2;
SA.build_sa(n);
reverse(a, a+n-2);
// 0 1 2 3 4 5 6 -> 6 5 4 3 2 1 0 sa[0] 对应的是 n-2 n = 9 n - 3 - sa[0]
int Cut = n - 3 - SA.sa[0];
reverse(a, a+Cut+1);
memcpy(b, a, n*4);
reverse(a+Cut+1, a+n-1);
memcpy(SA.s, a+Cut+1, (n-2-Cut)*4);
memcpy(a, b, n*4);
reverse(a+Cut+1, a+n);
memcpy(SA.s+n-2-Cut, a+Cut+1, n-Cut-1);
SA.n = n - 2 - Cut + n - Cut - 1;
SA.build_sa(n);
int Cut2;
for (i = 0; i < SA.n; ++i)
if (SA.sa[i] < n - 2 - Cut){
Cut2 = n - 3 - Cut - SA.sa[i] + Cut + 1 ;
break;
}
memcpy(a, b, n*4);
reverse(a+Cut+1, a+Cut2+1);
reverse(a+Cut2+1, a+n);
for (i = 0; i < n; ++i) printf("%d\n", v[a[i]]);
return 0;
}
/*
3 1 2 3 1 5
5 1 3 2 1 3 2 1 3 2 5 1 3 2 1 3 2 1
*/