[EC Final 2022] Minimum Suffix
又没做出来,思路卡在如何处理 Duval 算法带给我们的信息上。
Lyndon 题。首先这个 \(p_i\) 其实是告诉了我们每一个前缀的 Lyndon 分解的,因为我们知道 Lyndon 分解有这样一个求法,对于一个完全是由 Lyndon 串组成的字符串的分解(不是 Lyndon 分解),取出相邻两项 \(u,v\) 满足 \(u<v\),合并这两个串,不断做下去就得到了原串的 Lyndon 分解。而最小后缀其实就是最后一个 Lyndon word,这样维护一个栈,那么每次加入一个字符后会合并一段后缀,合并的长度由 \(p_i\) 决定。
如何利用这个信息呢?一个想法是直接 Duval,但是你会发现你几乎没有办法简单刻画类 Lyndon 串。还有你加入一个字符的时候,具体怎么对待这些串还需要看后续它们是否会合并起来,因为后面的 \(p_i\) 也会给前面的决策带来偏序限制。于是我便开了 Sol。
Sol 的想法形如:我们不如考虑一开始就求出整串的 Lyndon 结构,然后对于每一个 Lyndon 串来说分别解决,此时每一个串后续一定会合并起来而且合并成恰好一个串!这样处理时我们压根不用考虑最难搞的 \(s_k>s_j\) 的情况。
处理完单个 Lyndon 串,我们会得到一个由 = 与 < 组成的树形结构。Lyndon 串与串还有 \(\ge\) 的字典序限制。
从后往前贪心,单个 Lyndon 串内从前往后贪心,为了满足串与串之间的限制需要精细调整。调整不难但是极其细节,我调整写挂了,疯狂修才修好了,但是复杂度被我修假了,这份代码那个败笔 goto 语句好像让复杂度没了保证。
#include <cstdio>
#include <algorithm>
using namespace std;
int read(){
char c=getchar();int x=0;
while(c<48||c>57) c=getchar();
do x=x*10+(c^48),c=getchar();
while(c>=48&&c<=57);
return x;
}
const int N=3000003;
int p[N],n;
int stk[N],tp;
bool eq[N];int las[N];
int a[N];
void solve(){
n=read();
for(int i=1;i<=n;++i) p[i]=read();
tp=0;
for(int i=1;i<=n;++i){
stk[++tp]=i;
while(tp&&stk[tp]>p[i]) --tp;
if(!tp||stk[tp]!=p[i]){puts("-1");return;}
}
stk[tp+1]=n+1;
for(int i=1;i<=tp;++i){
int ps=stk[i];
for(int x=stk[i]+1;x<stk[i+1];++x){
las[x]=ps;
if(p[x]==stk[i]){eq[x]=0,ps=p[x];continue;}
if(p[x]-x==p[ps]-ps){eq[x]=1,++ps;continue;}
puts("-1");return;
}
}
for(int i=tp;i;--i){
a[stk[i]]=1;
for(int x=stk[i]+1;x<stk[i+1];++x){
if(eq[x]) a[x]=a[las[x]];
else a[x]=a[las[x]]+1;
}
tmp:
if(i<tp){
int cmp=0,ps=0;
for(int x=stk[i],y=stk[i+1];x<stk[i+1]&&y<stk[i+2];++x,++y){
if(a[x]>a[y]){cmp=1;ps=x;break;}
if(a[x]<a[y]){cmp=-1;ps=x;break;}
}
if(!cmp){
if(stk[i+1]-stk[i]>stk[i+2]-stk[i+1]) cmp=1;
if(stk[i+1]-stk[i]<stk[i+2]-stk[i+1]) cmp=-1,ps=stk[i+1]-1;
}
if(cmp>=0) continue;
bool fl=0;
while(ps>stk[i]&&eq[ps]) --ps,fl=1;
if(fl){
a[ps]=a[ps-stk[i]+stk[i+1]]+1;
for(int x=ps+1;x<stk[i+1];++x){
if(eq[x]) a[x]=a[las[x]];
else a[x]=a[las[x]]+1;
}
continue;
}
else{
a[ps]=a[ps-stk[i]+stk[i+1]]+(ps==stk[i+1]-1&&ps-stk[i]+stk[i+1]+1<stk[i+2]);
for(int x=ps+1;x<stk[i+1];++x){
if(eq[x]) a[x]=a[las[x]];
else a[x]=a[las[x]]+1;
}
goto tmp;
}
}
}
for(int i=1;i<=n;++i) printf("%d ",a[i]);
putchar('\n');
}
int main(){
int tc=read();
while(tc--) solve();
return 0;
}

浙公网安备 33010602011771号