把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

【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;//输出答案
}
posted @ 2020-05-31 18:25  TheLostWeak  阅读(84)  评论(0编辑  收藏  举报