版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88812977
传送门
解析:
首先可以很显然的发现长度为 的答案肯定为 。
考虑倒着处理。
我们发现,在长度变短的过程中,有一些串逐渐变得相同,如果在某个长度 , ,且 ,(其中 表示以 开头,且长度为当前讨论长度的子串。)则 在之后都不可能成为任何位置的答案,因为总有一个字典序小于等于它的 在它左边。
单调栈维护这个关系就行了。
比较字典序我采用的是Hash+二分。
代码:
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc getchar
#define cs const
namespace IO{
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cerr;
using std::cout;
using std::swap;
cs int N=3e5+5;
int n,m;
char s[N];
int a[N];
namespace Hash{
typedef unsigned long long u64;
cs u64 Base=47,Base2=131;
u64 h[N],Pow[N];
inline void init(){
Pow[0]=1;
for(int re i=1;i<=n;++i){
Pow[i]=Pow[i-1]*Base;
h[i]=h[i-1]*Base+a[i];
}
}
inline u64 get(int l,int r){
return h[r]-h[l-1]*Pow[r-l+1];
}
}
inline bool equal(int l1,int l2,int len){
return Hash::get(l1,l1+len-1)==Hash::get(l2,l2+len-1);
}
inline bool cmp(int l1,int l2,int len){
if(equal(l1,l2,len))return true;
int l=1,r=len,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(equal(l1,l2,mid))l=mid+1,ans=mid;
else r=mid-1;
}
return a[l1+ans]<=a[l2+ans];
}
int sta[N],top;
int ans[N];
signed main(){
std::ios::sync_with_stdio(false);
m=getint();n=getint();
if(m==26){
scanf("%s",s+1);
for(int re i=1;i<=n;++i)a[i]=s[i];
}
else for(int re i=1;i<=n;++i)a[i]=getint();
Hash::init();
for(int re i=1;i<=n;++i){
sta[++top]=i;
while(top>1&&cmp(sta[top-1],sta[top],n-i+1))--top;
ans[n-i+1]=sta[top];
}
for(int re i=1;i<=n;++i)cout<<ans[i]<<" ";
return 0;
}