Solution P12008 【MX-X10-T4】[LSOT-4] Fragment of Memories
UniGravity · · 题解
鲜花:Milthm 真的很好玩!111
感谢 @良心WA题人 指出了题解复杂度分析的错误。重写了复杂度分析。
首先有一种
考虑优化单次 check 的复杂度,一次快速跳一整个长度为
然后观察
考虑双指针加上 check 判断。假设当前的区间为
- 如果 check 失败,则已经找到了
x 的答案,接下来x\gets x+1,m\gets m-1 。发现左端点右移,右端点不变。 - 如果 check 成功,则变成
m\gets m+1 ,右端点向右。
若每次 check 复杂度只和上次区间移动时变化的端点的出现次数(即
于是做完了。时间复杂度
const int N=2000005;
int n,k,V,a[N],nxt[22][N],nv[22][N],pre[N];
il bool check(int bs,int m){
int p=pre[bs],c,p1,p2;if(!p)return 0;
// cerr<<"check "<<bs<<' '<<m<<'\n';
forto(i,1,k){
c=m-1,p1=p;
forbk(t,21,0)if((1<<t)<=c)c-=1<<t,p1=nxt[t][p1];//,cerr<<t<<','<<p1<<' ';cerr<<'\n';
// cerr<<p<<' '<<m<<' '<<p1<<'\n';
if(!p1)return 0;
if(i==k)return 1;
p2=p;
forbk(t,21,0)if(nv[t][p2]&&nv[t][p2]<=p1)p2=nv[t][p2];
p2=nv[0][p2];if(!p2)return 0;
p=p2;
}
return 1;
}
signed main(){
n=read(),k=read(),V=read();
forto(i,1,n)a[i]=read();
forbk(i,n,1)nv[0][i]=pre[a[i]],nxt[0][i]=pre[a[i]+1],pre[a[i]]=i;
// forto(i,1,n)cerr<<nxt[0][i]<<' ';cerr<<'\n';
forto(t,1,21)forto(i,1,n)nxt[t][i]=nxt[t-1][nxt[t-1][i]],nv[t][i]=nv[t-1][nv[t-1][i]];
int ans=0;
forto(i,1,V){
while(check(i,ans+1))ans++;
printf("%d ",ans);
if(ans)ans--;
}
puts("");
return 0;
}