题意:
给定一个数列,第一项比其他任何项都要大,要求分成三份,不能为空,分成三份后,再翻转,求最小的序列。
思路:
首先是把串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