pku3581 Sequence
搞掂这题我用了三张草稿纸。。。这得感谢我的小学班主任黄向阳老师,您在我毕业的时候塞给我的n叠作文纸,直到现在还没用完,搞得我每撕一张就想您一次。。。
(省略一万字)
说说我的做法,这题用后缀数组不难想,但要注意以下几点:
1,假设要分开的是两段而不是三段,看看以下两个数据:
2 1 2 1 3 -> 1 2 1 2 3 (1)
2 1 2 1 0 -> 1 2 0 1 2 (2)
看得出两个数据分段的地方不一样。可以试一试最后的数字分别是0、1、2、3的情况,会发现当最后的数字大于等于3时有最小字典序的串按(1)来分段,小于3时按(2)来分段,也就是说分段情况是由最后一个数字决定的。有了这个结论,我的做法是先将原串置反,然后将逆串的第一个数字加到逆串的末尾跑后缀数组,得出的长度不大于原串长度-2的最小后缀就是第一段输出。从逆串中去掉第一段后再按以上步骤得出第二段输出,剩下的就是第三段了。总共跑了两趟后缀数组。(这里错了,正解看评论)
2,如果后缀数组当中用到了桶排序,一定要先将串离散化,不然桶装不下。
3,用while(scanf()!=EOF)真的会WA,至于为什么呢我也不清楚。
#include <iostream>
#include <algorithm>
using namespace std;
#define MAXN 200010
int b[MAXN],array[4][MAXN],*rank,*nrank,*sa,*nsa,n,len;
int seq[MAXN];
int mx;
int num[MAXN],change[MAXN];
void make_sa(){
int i,k;
sa=array[0];
nsa=array[1];
rank=array[2];
nrank=array[3];
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
b[seq[i]]++;
for(i=1;i<=mx;i++)
b[i]+=b[i-1];
for(i=n-1;i>=0;i--)
sa[--b[seq[i]]]=i;
for(rank[sa[0]]=0,i=1;i<n;i++){
rank[sa[i]]=rank[sa[i-1]];
if(seq[sa[i]]!=seq[sa[i-1]])
rank[sa[i]]++;
}
for(k=1;k<n && rank[sa[n-1]]<n-1;k*=2){
for(i=0;i<n;i++)
b[rank[sa[i]]]=i;
for(i=n-1;i>=0;i--)
if(sa[i]-k>=0)
nsa[b[rank[sa[i]-k]]--]=sa[i]-k;
for(i=n-k;i<n;i++)
nsa[b[rank[i]]--]=i;
for(nrank[nsa[0]]=0,i=1;i<n;i++){
nrank[nsa[i]]=nrank[nsa[i-1]];
if(rank[nsa[i]]!=rank[nsa[i-1]] || rank[nsa[i]+k]!=rank[nsa[i-1]+k])
nrank[nsa[i]]++;
}
int *t=sa;sa=nsa;nsa=t;
t=rank;rank=nrank;nrank=t;
}
}
class CP{
public:
int operator()(int a,int b){
return num[a]<num[b];
}
};
void init(){
int i;
scanf("%d",&n);
mx=n;//桶排序的范围在1~mx
for(i=n-1;i>=0;i--){
scanf("%d",&num[i]);
b[i]=i;
}
sort(b,b+n,CP());
int m=1;
seq[b[0]]=1;
change[1]=num[b[0]];
for(i=1;i<n;i++){
if(num[b[i]]!=num[b[i-1]])
m++;
seq[b[i]]=m;
change[m]=num[b[i]];
}
}
int main(){
int i,cnt,t;
init();
seq[n++]=seq[0];//*
make_sa();
t=0;
while(sa[t]==n-1 || sa[t]<=1)t++;
cnt=0;
for(i=sa[t];i<n-1;i++){
cnt++;
printf("%d\n",change[seq[i]]);
}
n-=cnt+1;
seq[n++]=seq[0];//*
make_sa();
t=0;
while(sa[t]==n-1 || sa[t]<1)t++;
for(i=sa[t];i<n-1;i++)
printf("%d\n",change[seq[i]]);
for(i=0;i<sa[t];i++)
printf("%d\n",change[seq[i]]);
return 0;
}
#include <algorithm>
using namespace std;
#define MAXN 200010
int b[MAXN],array[4][MAXN],*rank,*nrank,*sa,*nsa,n,len;
int seq[MAXN];
int mx;
int num[MAXN],change[MAXN];
void make_sa(){
int i,k;
sa=array[0];
nsa=array[1];
rank=array[2];
nrank=array[3];
memset(b,0,sizeof(b));
for(i=0;i<n;i++)
b[seq[i]]++;
for(i=1;i<=mx;i++)
b[i]+=b[i-1];
for(i=n-1;i>=0;i--)
sa[--b[seq[i]]]=i;
for(rank[sa[0]]=0,i=1;i<n;i++){
rank[sa[i]]=rank[sa[i-1]];
if(seq[sa[i]]!=seq[sa[i-1]])
rank[sa[i]]++;
}
for(k=1;k<n && rank[sa[n-1]]<n-1;k*=2){
for(i=0;i<n;i++)
b[rank[sa[i]]]=i;
for(i=n-1;i>=0;i--)
if(sa[i]-k>=0)
nsa[b[rank[sa[i]-k]]--]=sa[i]-k;
for(i=n-k;i<n;i++)
nsa[b[rank[i]]--]=i;
for(nrank[nsa[0]]=0,i=1;i<n;i++){
nrank[nsa[i]]=nrank[nsa[i-1]];
if(rank[nsa[i]]!=rank[nsa[i-1]] || rank[nsa[i]+k]!=rank[nsa[i-1]+k])
nrank[nsa[i]]++;
}
int *t=sa;sa=nsa;nsa=t;
t=rank;rank=nrank;nrank=t;
}
}
class CP{
public:
int operator()(int a,int b){
return num[a]<num[b];
}
};
void init(){
int i;
scanf("%d",&n);
mx=n;//桶排序的范围在1~mx
for(i=n-1;i>=0;i--){
scanf("%d",&num[i]);
b[i]=i;
}
sort(b,b+n,CP());
int m=1;
seq[b[0]]=1;
change[1]=num[b[0]];
for(i=1;i<n;i++){
if(num[b[i]]!=num[b[i-1]])
m++;
seq[b[i]]=m;
change[m]=num[b[i]];
}
}
int main(){
int i,cnt,t;
init();
seq[n++]=seq[0];//*
make_sa();
t=0;
while(sa[t]==n-1 || sa[t]<=1)t++;
cnt=0;
for(i=sa[t];i<n-1;i++){
cnt++;
printf("%d\n",change[seq[i]]);
}
n-=cnt+1;
seq[n++]=seq[0];//*
make_sa();
t=0;
while(sa[t]==n-1 || sa[t]<1)t++;
for(i=sa[t];i<n-1;i++)
printf("%d\n",change[seq[i]]);
for(i=0;i<sa[t];i++)
printf("%d\n",change[seq[i]]);
return 0;
}