- /*
- Title: Sequence
- Author: Jeff
- Time: 2008/10/29
- Complexity: O(N*log(N));
- Result: 7364K 1829MS/ AC
- Reference:
- Discuss
- Description:
- 给定一个数组{A1, A2, …, An} 满足A1 > A2, …, An,
- 把该数组分成三段,单独翻转,使得数组的字典序最小。
- Tips:
- 后缀数组。
- 输入数据时候反序输入,再求后继数组。
- 比如原始数据:
- 6
- 10 1 1 2 3 4
- 反序输入就是
- 4 3 2 1 1 10
- 第一部分就是满足能将该序列分成三段的排在最前的后缀数。就是 1 1 10 了。
- 去掉这一部分之后再求一次后缀数组,
- 第二部分就是满足能将该序列分成两段的最大的后缀数。就是 2
- 再输出最后一部分 4 3
- 结果 1 1 10 2 4 3
- 为什么要求两次后缀数组呢,看下面一组数据
- 7
- 5 0 2 1 2 1 3
- (反序) 3 1 2 1 2 0 5
- 按照第一次求后缀数组的结果:
- 一:0 5
- 二:1 2 (因为后缀1 2 0 5比1 2 1 2 0 5要小)
- 三:3 1 2
- 最后结果:0 5 1 2 3 1 2 (WA)
- 所以要去掉第一段结果再求一次后缀数组:
- (二三段反序) 3 1 2 1 2
- 现在后缀1 2 1 2 比 1 2要小,所以得到正确结果:
- 二:1 2 1 2
- 三:3
- 最后结果:0 5 1 2 1 2 3
- p.s.
- 只求一次后缀数组,结果WA掉了。。。
- */
- #include <cstdio>
- #include <cstring>
- #include <algorithm>
- using namespace std;
- const int MAX = 200001;
- struct Sfx{
- int idx;
- int key[2];
- bool operator<(const Sfx &other)const{
- return key[0] < other.key[0] ||
- key[0] == other.key[0] && key[1] < other.key[1];
- }
- };
- Sfx g_sfx[2][MAX], *sa = g_sfx[0], *temp_sa = g_sfx[1];
- int cnt[MAX];
- int rank[MAX];
- int A[MAX];
- int n;
- void cSort(Sfx *in, int key, Sfx *out){
- memset(cnt, 0, sizeof(cnt));;
- for(int i = 0; i < n; i++)
- cnt[in[i].key[key]]++;
- for(int i = 1; i < n; i++)
- cnt[i] += cnt[i-1];
- for(int i = n - 1; i >= 0; i--)
- out[ --cnt[in[i].key[key]] ] = in[i];
- }
- void build_sfx(){
- for(int i = n-1; i >= 0; i--){
- sa[i].idx = sa[i].key[1] = i;
- sa[i].key[0] = A[i];
- }
- sort(sa, sa+n);
- for(int i = 0; i < n; i++)sa[i].key[1] = 0;
- int wid = 1;
- while(wid < n){
- rank[sa[0].idx] = 0;
- for(int i = 1; i < n; i++){
- rank[sa[i].idx] = rank[sa[i-1].idx];
- if(sa[i-1] < sa[i])rank[sa[i].idx]++;
- }
- for(int i = 0; i < n; i++){
- sa[i].idx = i;
- sa[i].key[0] = rank[i];
- sa[i].key[1] = i + wid < n ? rank[i + wid] : 0;
- }
- cSort(sa, 1, temp_sa); cSort(temp_sa, 0, sa);
- wid *= 2;
- }
- //printf("/n");for(int i = 0; i < n; i++)printf("%d ", A[i]);printf("/n");
- //printf("sa: ");for(int i = 0; i < n; i++)printf("%d ", sa[i].idx);printf("/n");
- //printf("r: ");for(int i = 0; i < n; i++)printf("%d ", rank[i]); printf("/n");
- }
- int main(){
- freopen("in.txt", "r", stdin);
- freopen("out.txt", "w", stdout);
- while(scanf("%d", &n) != EOF){
- for(int i = n-1; i >= 0; i--)
- scanf("%d", &A[i]);
- build_sfx();
- int ans[4];
- ans[0] = n;
- for(int i = 0, j = 1; j <= 1; i++){
- if(sa[i].idx < ans[j-1])
- if(sa[i].idx >= 3 - j){
- ans[j] = sa[i].idx;
- for(int k = ans[j]; k < ans[j-1]; k++)
- printf("%d/n", A[k]);
- j++;
- }
- }
- n = ans[1];
- build_sfx();
- for(int i = 0, j = 2; j <= 2; i++){
- if(sa[i].idx < ans[j-1])
- if(sa[i].idx >= 3 - j){
- ans[j] = sa[i].idx;
- for(int k = ans[j]; k < ans[j-1]; k++)
- printf("%d/n", A[k]);
- j++;
- }
- }
- for(int k = 0; k < ans[2]; k++)printf("%d/n", A[k]);
- break;
- //printf("/n");
- }
- return 0;
- }
PKU 3581 Sequence 解题报告
最新推荐文章于 2021-05-29 20:29:15 发布