题目链接:http://poj.org/problem?id=3581
题目大意:给一个数列,要求将其分成三段,每段进行翻转后形成后合并成新数列,求按字典顺序最小的新数列。
思路:
注意到题目中数列a0,a2,a3...an-1, a0是最大的,因此将原数列翻转后an-1,an-2,...,a1,a0,求后缀数组,
sa[0]所代表的后缀即为所求第一段翻转后的数列,注意到要分成三份,因此sa[0]<2时不可取,此时找sa[1],
sa[2]看是否可取。找第一个位置后,设剩下 数列是an-1,an-2,...,ak, 问题转化为找一个分割位置m,使得
am,..ak, an-1,an-2,...,am+1,字典顺序最小。因此将原数列扩展成an-1,an-2,...,ak,an-1,an-2,...,ak,求后缀数组
这样,找到一个最小的i, 使得sa[i]>0, sa[i]<n-k(即要在前一部分),则m=sa[i]. 此时后缀sa[i]的前n-k个前缀刚好是
要求的翻转后的第二三部分。
另外就是要进行离散化,但要保证原数列之间的相对大小关系。
详细代码:
1 #include <map> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #define rank rk 6 using namespace std; 7 8 const int maxn=200010; 9 int s[maxn]; 10 int n; 11 int sa[maxn],t[maxn],t2[maxn],c[maxn]; 12 // 后缀数组模板 13 void build_sa(int m){ 14 int *x=t, *y=t2; 15 memset(c, 0, sizeof(int)*m); 16 for(int i=0; i<n; ++i) c[x[i]=s[i]]++; 17 for(int i=1; i<m; ++i) c[i]+=c[i-1]; 18 for(int i=n-1; i>=0; --i) sa[--c[x[i]]]=i; 19 for(int k=1; k<=n; k<<=1){ 20 int p=0; 21 for(int i=n-k; i<n; ++i) y[p++]=i; 22 for(int i=0; i<n; ++i) 23 if(sa[i]>=k) y[p++]=sa[i]-k; 24 memset(c, 0, sizeof(int)*m); 25 for(int i=0; i<n; ++i) c[x[y[i]]]++; 26 for(int i=1; i<m; ++i) c[i] += c[i-1]; 27 for(int i=n-1; i>=0; --i) sa[--c[x[y[i]]]]=y[i]; 28 std::swap(x,y); 29 y[n]=-1; 30 p=1; x[sa[0]]=0; 31 for(int i=1; i<n; ++i) 32 x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p-1:p++; 33 m=p; 34 if(p>=n) break; 35 } 36 } 37 // 用于离散化 38 map<int,int> src2i, i2src; 39 map<int,int>::iterator it; 40 41 void print(int i, int t){ 42 while(i<t){ 43 printf("%d ", i2src[s[i++]]); 44 } 45 } 46 int main(){ 47 scanf("%d", &n); 48 for(int i=0; i<n; ++i){ 49 scanf("%d", &t[i]); 50 src2i[t[i]]=1; 51 } 52 int cnt=1; 53 for(it=src2i.begin(); it!=src2i.end(); ++it){ 54 i2src[cnt]=it->first; 55 it->second=cnt++; 56 } 57 for(int i=0; i<n; ++i) 58 s[n-1-i]=src2i[t[i]]; 59 build_sa(maxn); 60 int idx1=sa[0], i=1; 61 while(idx1<2) idx1=sa[i++]; 62 print(idx1, n); 63 copy(s, s+idx1, s+idx1);// 扩展数组 64 n=2*idx1; build_sa(maxn); 65 int idx2=sa[0]; i=1; 66 while(idx2>=idx1 || idx2<1) idx2=sa[i++]; 67 print(idx2, idx2+idx1); 68 return 0; 69 }