标签:
题意:
给定一个数列,第一项比其他任何项都要大,要求分成三份,不能为空,分成三份后,再翻转,求最小的序列。
思路:
首先是把串map,然后反转一下。
接着求一下sa,很明显第一次切的地方一定是sa[i]>1的第一个最小的位置。
接着就是第二刀了。
很明显不能直接再找sa[i]第二小的。
因为第一刀之所以能那样切是因为数列的第一个数一定比其他都大。
那么我们需要把剩下的串复制一份拼接到后面去,再求一次sa。
为什么要这样做呢?
是因为我们要找切的地方,切完之后就肯定与前面的相连,所以找到到最小的。
就连起来找。
这里给几组样例:
7
10 0 2 2 2 2 1
7
10 0 2 2 2 2 3
最后特别注意下,这题多实例会WA,必须单实例。
代码:
#include"cstdlib" #include"cstdio" #include"cstring" #include"cmath" #include"queue" #include"algorithm" #include"iostream" #include"map" #include"vector" #define ll long long using namespace std; #define N 212054 int wa[N],wb[N],wv[N],wws[N]; int sa[N],ra[N],height[N]; int fuck[N],kx[N]; int v[N]; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int n,int m) { int i,j,p,*x=wa,*y=wb; for(i=0; i<m; i++) wws[i]=0; for(i=0; i<n; i++) wws[x[i]=v[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[x[i]]]=i; for(j=1,p=1; p<n; j*=2,m=p) { for(i=n-j,p=0; i<n; i++) y[p++]=i; for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; for(i=0; i<n; i++) wv[i]=x[y[i]]; for(i=0; i<m; i++) wws[i]=0; for(i=0; i<n; i++) wws[wv[i]]++; for(i=1; i<m; i++) wws[i]+=wws[i-1]; for(i=n-1; i>=0; i--) sa[--wws[wv[i]]]=y[i]; for(swap(x,y),p=1,i=1,x[sa[0]]=0; i<n; i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],j)?p-1:p++; } return ; } int main() { int n; scanf("%d",&n); for(int i=0; i<n; i++) scanf("%d",&fuck[i]); memcpy(v,fuck,sizeof(fuck)); sort(fuck,fuck+n); map<int,int>mp; for(int i=0; i<n; i++) { mp[fuck[i]]=i+5; kx[i+5]=fuck[i]; } for(int i=0; i<=(n-1)/2; i++) swap(v[i],v[n-1-i]); for(int i=0; i<n; i++) v[i]=mp[v[i]]; v[n]=0; da(n+1,n+10); int f1,f2; for(int i=1; i<=n; i++) { if(sa[i]>1) { f1=sa[i]; break; } } for(int i=f1; i<n; i++) printf("%d\n",kx[v[i]]); for(int i=0;i<f1;i++) v[i+f1]=v[i]; v[2*f1]=0; da(2*f1+1,n+10); for(int i=1;i<=2*f1;i++) { if(sa[i]>0 && sa[i]<f1) { f2=sa[i]; break; } } for(int i=f2; i<f1; i++) printf("%d\n",kx[v[i]]); for(int i=0; i<f2; i++) printf("%d\n",kx[v[i]]); puts(""); return 0; }
标签:
原文地址:http://blog.csdn.net/wdcjdtc/article/details/45040113