poj3581 Sequence(后缀数组sa的运用+离散化)
2015-09-21 17:30
447 查看
题目链接:点击打开链接
题意描述:给定一个整数序列,序列的第一个元素大于其余所有的元素,先把序列截成三段,然后对每一段进行逆转,求新生成的序列中字典序最小的序列?
解题思路:后缀数组sa的运用+离散化
分析:
先分析第一段:
![](http://img.blog.csdn.net/20150921171849935?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center)
如图所示表示目标序列,对第一段的长度进行讨论,其中红色1表示第一个元素,也就是最大值
1、如果上面三个序列在0~1区间不等,那么我们选取字典序较小的即可,否则我们在第1和第2个之间选取
2、如果前两个序列在1~2区间上不等,那么我们选取字典序较小的即可,否则我们选取第一个
从上述讨论我们发现对于第一段的选取我们需要选出逆序后字典序最小的即可采用后缀数组可以很容易解决
对于第二段和第三段的选取,我们可以把剩下的序列逆序重复两遍之后找字典序最小的即可
如x1~x2y1~y2z1~z2其中x1~x2已经确定,如果使剩下的最小呢?即:y2~y1z2~z1
我们只需要构造出这样的序列即可:z2~z1y2~y1z2~z1y2~y1
使用后缀数组sa可以很容易解决这个问题
代码:
题意描述:给定一个整数序列,序列的第一个元素大于其余所有的元素,先把序列截成三段,然后对每一段进行逆转,求新生成的序列中字典序最小的序列?
解题思路:后缀数组sa的运用+离散化
分析:
先分析第一段:
如图所示表示目标序列,对第一段的长度进行讨论,其中红色1表示第一个元素,也就是最大值
1、如果上面三个序列在0~1区间不等,那么我们选取字典序较小的即可,否则我们在第1和第2个之间选取
2、如果前两个序列在1~2区间上不等,那么我们选取字典序较小的即可,否则我们选取第一个
从上述讨论我们发现对于第一段的选取我们需要选出逆序后字典序最小的即可采用后缀数组可以很容易解决
对于第二段和第三段的选取,我们可以把剩下的序列逆序重复两遍之后找字典序最小的即可
如x1~x2y1~y2z1~z2其中x1~x2已经确定,如果使剩下的最小呢?即:y2~y1z2~z1
我们只需要构造出这样的序列即可:z2~z1y2~y1z2~z1y2~y1
使用后缀数组sa可以很容易解决这个问题
代码:
#include <cstdio> #include <algorithm> #include <iostream> using namespace std; const int N = 400010; int cmp(int *r,int a,int b,int l) { return (r[a]==r[b]) && (r[a+l]==r[b+l]); } int wa ,wb ,ww ,wv ; void DA(int *r,int *sa,int n,int m) //此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界 { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) ww[i]=0; for(i=0; i<n; i++) ww[x[i]=r[i]]++; for(i=1; i<m; i++) ww[i]+=ww[i-1]; for(i=n-1; i>=0; i--) sa[--ww[x[i]]]=i; //预处理长度为1 for(j=1,p=1; p<n; j*=2,m=p) //通过已经求出的长度J的SA,来求2*J的SA { for(p=0,i=n-j; i<n; i++) y[p++]=i; // 特殊处理没有第二关键字的 for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; //利用长度J的,按第二关键字排序 for(i=0; i<n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) ww[i]=0; for(i=0; i<n; i++) ww[wv[i]]++; for(i=1; i<m; i++) ww[i]+=ww[i-1]; for(i=n-1; i>=0; i--) sa[--ww[wv[i]]]=y[i]; //基数排序部分 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; //更新名次数组x[],注意判定相同的 } } struct node { int v,rk,id; } st ; bool cmp1(node a,node b) { return a.v<b.v; } bool cmp2(node a,node b) { return a.id<b.id; } int n,str ,sa ,ans ; int main() { scanf("%d",&n); for(int i=0; i<n; ++i){ scanf("%d",&st[i].v);st[i].id=i; } sort(st,st+n,cmp1); int rk=1; st[0].rk=rk++; ans[st[0].rk]=st[0].v; for(int i=1; i<n; ++i){ if(st[i].v==st[i-1].v) st[i].rk=st[i-1].rk; else{ st[i].rk=rk++;ans[st[i].rk]=st[i].v; } } sort(st,st+n,cmp2); for(int i=0; i<n-2; ++i) str[i]=st[n-2-i-1].rk; str[n-2]=0; DA(str,sa,n-1,rk); int len1=sa[1]; for(int i=len1; i<n-2; ++i) printf("%d\n",ans[str[i]]); int m=len1+2; for(int i=0; i<m; i++) str[m-i-1]=str[2*m-i-1]=st[i+n-m].rk; n=m; str[2*n]=0; DA(str,sa,2*n+1,rk);///2*n+1 int x; for(int i=1; i<=2*n; ++i)///问题1 if(sa[i]>0&&sa[i]<n){ x=sa[i];break;} for(int i=0; i<n; ++i) printf("%d\n",ans[str[x+i]]); return 0; }
相关文章推荐
- ThreadPoolExecutor使用和思考-线程池大小设置与BlockingQueue的三种实现区别
- Opencv3.0+opencv_contrib_lib +VS2013(编译)+CMake-gui(最近的版本都可以)
- 判断 Fragment 的 UI 是否可见
- UML建模之时序图(Sequence Diagram)
- 【UIFramework】前端UI框架—导航条
- java中queue的使用
- requestWindowFeature()的应用
- android NotificationCompat.Builder 使用
- 15.Android 异步更新UI 技巧
- DBCP针对不同数据库的validationQuery
- 递归-快速排序quickSort
- 字符串 intValue、floatValue、doubleValue、longLongValue 方法可以正确转换的位数或者大小
- iOS经典讲解之UICollectionView
- A new session could not be created. (Original error: Requested a new session but one was in progress) )错误解决办法
- POJ 2533 Longest Ordered Subsequence (DP动态规划)
- PAT研究生入学考试2015.03第四题Build A Binary Search Tree (30) 题解
- List<data> 数据转为easyui-datagrid json数据格式
- UILabel自适应高、宽
- 开源中国源码学习UI篇(一)之FragmentTabHost的使用分析
- SharePoint Search之(两)持续抓取Continues crawl