POJ3581 Sequence(后缀数组)
2016-03-04 20:50
561 查看
题意:给一个串,串的第一个字符比后面的都大,要把它分成三段,然后反转每一段,求能得到的字典序最小的串是什么。
首先,第一段是可以确定的:把原串反转,因为第一个字符是最大的,它是唯一的,不存在反转串的后缀之间有包含关系,所以取最小的后缀这就是第一段的字符串;
然后后面两段,如果确定分割位置可以发现这两段字符串构成是一个从分割位置出发逆时针循环回来的串——
即接下来要求的就是剩余部分的反转的最小表示,可以用后缀数组来做:把串加长一倍,答案就在最小的且长度大于等于原串长度的后缀了。
注意,分的段要非空。。所以还要在第一段、后面两段的分割加些判断。
这题好难A,不知道为什么。。WA来WA去。。改啊改,终于RE来RE去。。跟着别人把数字离散化后才AC了。。
首先,第一段是可以确定的:把原串反转,因为第一个字符是最大的,它是唯一的,不存在反转串的后缀之间有包含关系,所以取最小的后缀这就是第一段的字符串;
然后后面两段,如果确定分割位置可以发现这两段字符串构成是一个从分割位置出发逆时针循环回来的串——
即接下来要求的就是剩余部分的反转的最小表示,可以用后缀数组来做:把串加长一倍,答案就在最小的且长度大于等于原串长度的后缀了。
注意,分的段要非空。。所以还要在第一段、后面两段的分割加些判断。
这题好难A,不知道为什么。。WA来WA去。。改啊改,终于RE来RE去。。跟着别人把数字离散化后才AC了。。
#include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; #define MAXN 222222 int wa[MAXN],wb[MAXN],wv[MAXN],ws[MAXN]; int cmp(int *r,int a,int b,int l){ return r[a]==r[b] && r[a+l]==r[b+l]; } int sa[MAXN]; void SA(int *r,int n,int m){ int *x=wa,*y=wb; for(int i=0; i<m; ++i) ws[i]=0; for(int i=0; i<n; ++i) ++ws[x[i]=r[i]]; for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; for(int i=n-1; i>=0; --i) sa[--ws[x[i]]]=i; int p=1; for(int j=1; p<n; j<<=1,m=p){ p=0; for(int i=n-j; i<n; ++i) y[p++]=i; for(int i=0; i<n; ++i) if(sa[i]>=j) y[p++]=sa[i]-j; for(int i=0; i<n; ++i) wv[i]=x[y[i]]; for(int i=0; i<m; ++i) ws[i]=0; for(int i=0; i<n; ++i) ++ws[wv[i]]; for(int i=1; i<m; ++i) ws[i]+=ws[i-1]; for(int i=n-1; i>=0; --i) sa[--ws[wv[i]]]=y[i]; swap(x,y); x[sa[0]]=0; p=1; for(int i=1; i<n; ++i) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } } int a[MAXN],r[MAXN]; int b[MAXN],bn; int main(){ int n; scanf("%d",&n); for(int i=0; i<n; ++i){ scanf("%d",a+i); b[i]=a[i]; } sort(b,b+n); bn=unique(b,b+n)-b; for(int i=0; i<n; ++i){ a[i]=lower_bound(b,b+bn,a[i])-b+1; } for(int i=0; i<n; ++i){ r[i]=a[n-i-1]; } r =0; SA(r,n+1,bn+1); int m=0; for(int i=1; i<=n; ++i){ if(sa[i]>=2){ for(int j=sa[i]; j<n; ++j){ printf("%d\n",b[r[j]-1]); } n=sa[i]; for(int j=0; j<sa[i]; ++j){ r[j+sa[i]]=r[j]; m+=2; } r[m]=0; break; } } SA(r,m+1,bn+1); for(int i=1; i<=m; ++i){ if(m-sa[i]>=n && sa[i]!=m/2 && sa[i]!=0){ for(int j=0; j<n; ++j) printf("%d\n",b[r[sa[i]+j]-1]); break; } } return 0; }
相关文章推荐
- 中间透明的UIView实现的几种方法
- iOS UIBezierPath 路径裁剪
- ue4点滴
- Java StringBuilder & StringBuffer 源代码分析
- USACO 之 Section 1.4 More Search Techniques (已解决)
- 华为EMUI4.0 基于android 6.0的bug
- BlockingQueue
- Android源码浅析: Message/Handler/MessageQueue/Looper
- PAT (Advanced Level) Practise 1017 Queueing at Bank (25)
- [hdu4010]: Query on The Trees
- SPOJ QTREE Query on a tree [树链剖分+线段树]
- NSOperationQueue与GCD的使用原则和场景
- Android自动化测试(UiAutomator)介绍与学习
- UGUI源码学习之初涉Button(三)
- UIBezierPath精讲
- 消息队列ActiveMQ(一)——Queue方式和Topic方式
- require 加载机制
- UGUI源码学习之初涉Text(二)
- UITableView的全选和多选功能
- EasyUI Combobox 二级联动