poj3581
2015-11-29 18:07
267 查看
链接:点击打开链接
题意:给出N个数字组成的数列,将这N个数字分成三段并反转,求能得到的字典序最小的数列是什么(第一个数大于数列中的任意一个数)
代码:
题意:给出N个数字组成的数列,将这N个数字分成三段并反转,求能得到的字典序最小的数列是什么(第一个数大于数列中的任意一个数)
代码:
#include <cstdio> #include <string> #include <cstring> #include <iostream> #include <algorithm> using namespace std; int n,k; int rank[200005],tmp[200005]; bool cmp(int i,int j){ int ri,rj; if(rank[i]!=rank[j]) return rank[i]<rank[j]; ri=i+k<=n?rank[i+k]:-1; rj=j+k<=n?rank[j+k]:-1; return ri<rj; } void get_suffix(int *s,int *sa){ int i; // n=s.length(); for(i=0;i<=n;i++){ sa[i]=i; rank[i]=i<n?s[i]:-1; } for(k=1;k<=n;k*=2){ sort(sa,sa+n,cmp); tmp[sa[0]]=0; for(i=1;i<=n;i++) tmp[sa[i]]=tmp[sa[i-1]]+(cmp(sa[i-1],sa[i])?1:0); for(i=0;i<=n;i++) rank[i]=tmp[i]; } } //后缀数组模板 int s[200005],rev[200005],sa[200005]; int main(){ int i,j,ans1,ans2,tmp_n,temp; scanf("%d",&n); temp=n; for(i=0;i<n;i++) scanf("%d",&s[i]); reverse_copy(s,s+n,rev); //先将所有数字反转,第一段就是反转后后缀数组最小的 get_suffix(rev,sa); for(i=0;i<n;i++){ ans1=n-sa[i]; if(ans1>=1&&n-ans1>=2) //判断是否还能分成两段 break; } reverse_copy(s+ans1,s+n,rev); //将剩下的所有数字复制两次,如果直接找剩下的最小后 reverse_copy(s+ans1,s+n,rev+n-ans1);//数组则会在一些数据上产生错误,例如6 10 1 2 2 3 4 n=2*(n-ans1); //然后改变数组的长度n get_suffix(rev,sa); for(i=0;i<n;i++) if(sa[i]>=0&&sa[i]<n/2){ ans2=n/2-sa[i]+ans1; if(ans2-ans1>=1&&temp-ans2>=1) //判断是否还能反转 break; } reverse(s,s+ans1); reverse(s+ans1,s+ans2); reverse(s+ans2,s+temp); for(i=0;i<temp;i++) printf("%d\n",s[i]); return 0; }
相关文章推荐
- 欢迎使用CSDN-markdown编辑器
- 基于VM10+Win7安装Mac OSX10.11 El Capitan
- Fire Net
- ZOJ 3329 One Person Game [概率DP]
- leetcode Remove Duplicates from Sorted Array python
- android自定义View绘制天气温度曲线
- 控件与布局
- Android系统init.rc分析
- ORA-01012 not log on
- hdu 5586 Sum(dp+技巧)
- 2015/11/29 软件测试学习第一天 准备工作
- 黑马程序员——Java基础---访问修饰符
- 黑马程序员——Java基础---有关static(静态)的知识
- 黑马程序员——Java基础---递归
- 黑马程序员——Java基础---单例
- 黑马程序员——Java基础---面向对象之抽象
- Studio
- 1083. List Grades (25)
- Linux 命令神器 man与info
- setTimeout()和setInterval()看js的异步执行方法