/*
title: sequence
author: jeff
time: 2008/10/29
complexity: o(n*log(n));
result: 7364k 1829ms/ ac
reference:
discuss
description:
給定乙個陣列 滿足a1 > a2, …, an,
把該陣列分成三段,單獨翻轉,使得陣列的字典序最小。
tips:
字尾陣列。
輸入資料時候反序輸入,再求後繼陣列。
比如原始資料:
610 1 1 2 3 4
反序輸入就是
4 3 2 1 1 10
第一部分就是滿足能將該序列分成三段的排在最前的字尾數。就是 1 1 10 了。
去掉這一部分之後再求一次字尾陣列,
第二部分就是滿足能將該序列分成兩段的最大的字尾數。就是 2
再輸出最後一部分 4 3
結果 1 1 10 2 4 3
為什麼要求兩次字尾陣列呢,看下面一組資料
75 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
#include
#include
using
namespace std;
const
int max = 200001;
struct sfx
};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)
void build_sfx()
sort(sa, sa+n);
for(int i = 0; i < n; i++)sa[i].key[1] = 0;
int wid = 1;
while(wid < n)
for(int i = 0; i < n; i++)
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()
}n = ans[1];
build_sfx();
for(int i = 0, j = 2; j <= 2; i++)
}for(int k = 0; k < ans[2]; k++)printf("%d/n", a[k]);
break;
//printf("/n");
} return 0;
}
POJ3581 Sequence 字尾陣列)
大致題意 給出n個數,把這個數列分為三段,再把三段反轉後連線在一起成為乙個新串,求字典序最小的新串。大致思路 由於需要翻轉,所以在輸入時就按照反序輸入。比如樣例輸入是5 10 1 2 3 4。我們從後向前讀入就變為5 4 3 2 1 10。對這列數求出字尾陣列。在大於2的後最中找到最小的字尾並輸出。...
POJ3581 Sequence(字尾陣列)
題意 給乙個串,串的第乙個字元比後面的都大,要把它分成三段,然後反轉每一段,求能得到的字典序最小的串是什麼。首先,第一段是可以確定的 把原串反轉,因為第乙個字元是最大的,它是唯一的,不存在反轉串的字尾之間有包含關係,所以取最小的字尾這就是第一段的字串 然後後面兩段,如果確定分割位置可以發現這兩段字串...
字尾陣列 poj3581 Sequence
考慮第一次切割,必然切割的是翻轉後字典序最小的字首,偽證 若切割位置更靠前 則會導致第乙個數翻轉後更靠前,字典序必然更大。若切割位置更靠後,則顯然也會導致字典序更大。sa即可 對於第二次切割,有結論 將序列分割成兩段再分別翻轉得到的序列,可以看作是將兩個原序列拼接得到的新序列中的某個字串翻轉得到的序...