首页 > 代码库 > poj 3581 Sequence(后缀数组,离散化)详解
poj 3581 Sequence(后缀数组,离散化)详解
题目链接: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\n", 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 }
poj 3581 Sequence(后缀数组,离散化)详解
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。