【BZOJ2882】工艺(后缀数组一眼题)
大致题意: 给定一个\(n\)个数的环,让你把它断开,使得字典序最小。
前言
这道题在洛谷上只是道蓝题,大概有什么其他做法吧。。。
后缀数组
一眼题。显然只要把原串复制一遍然后后缀排序即可。
注意最后选择断开的位置应该是第一个小于等于\(n\)的\(SA_i\),一开始智障了。。。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 600000
using namespace std;
int n,a[N+5];
class FastIO
{
private:
#define FS 100000
#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
#define pc(c) (C==E&&(clear(),0),*C++=c)
#define D isdigit(c=tc())
int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
public:
I FastIO() {A=B=FI,C=FO,E=FO+FS;}
Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc(' ');}
I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
}F;
class SuffixArray
{
private:
int l,SA[N+5],rk[N+5],p[N+5],t[N+5];
I void Sort(CI S)//基数排序
{
RI i;for(i=0;i<=S;++i) t[i]=0;for(i=1;i<=l;++i) ++t[rk[i]];
for(i=1;i<=S;++i) t[i]+=t[i-1];for(i=l;i;--i) SA[t[rk[p[i]]]--]=p[i];
}
I void GetSA()//后缀排序
{
RI i;for(i=1;i<=l;++i) rk[p[i]=i]=a[i];
RI k,t=0,S=N;for(Sort(S),k=1;t^l;k<<=1,S=t)
{
for(t=0,i=1;i<=k;++i) p[++t]=l-k+i;for(i=1;i<=l;++i) SA[i]>k&&(p[++t]=SA[i]-k);
for(Sort(S),i=1;i<=l;++i) p[i]=rk[i];
for(rk[SA[1]]=t=1,i=2;i<=l;++i) rk[SA[i]]=
(p[SA[i-1]]^p[SA[i]]||p[SA[i-1]+k]^p[SA[i]+k])?++t:t;
}
}
public:
I int GetID(CI x)
{
l=x,GetSA();for(RI i=1;i<=l;++i) if(SA[i]<=n) return SA[i];//求出第一个小于等于n的SA
}
}S;
int main()
{
RI i,j,k;for(F.read(n),i=1;i<=n;++i) F.read(a[i]),a[n+i]=a[i];//复制一遍
for(k=S.GetID(n<<1),i=0;i^n;++i) F.write(a[k+i]);return F.clear(),0;//输出答案
}
待到再迷茫时回头望,所有脚印会发出光芒