【题解】arc165_b Sliding Window Sort 2
arc165_b Sliding Window Sort 2
题意
有一个长度为 \(n\) 的排列 \(p\),和整数 \(m\)。
你需要对排列进行恰好一次操作:
- 选定一个 \(i\),满足 \(i+m-1\le n\),将 \(p\) 中位于区间 \([i,i+m-1]\) 的元素升序排序。
求操作后能得到的字典序最大的排列。
题解
知识点:二分,单调栈,ST 表。
不同以往,求的是字典序最大的排列。
注意到,选定一个长度为 \(m\) 的区间排序后,排列的字典序一定不会变大,区间中越大的数会被排到越后面。
让更靠前面的 \(i\) 被换到后面去会导致字典序更小。
枚举 \(i\),此时排序区间为 \([i,i+m-1]\),但并不意味着会 \(i\) 会被换到后面去,可能存在一段区间的前缀在排序后位置都不变。
所以要找到 \([i,i+m-1]\) 中第一个会被换到后面去的数的下标 \(k\),这才会真正影响排列的字典序大小。
对于 \((i,k)\),当 \(k\) 不同时,选定 \(k\) 越大越优,目的显然。而 \(k\) 相同时,\(i\) 越小越优,目的是让受影响的区间 \([k,i+m-1]\) 长度尽可能小。
对一个 \(i\),怎么快速找对应的 \(k\)?
\(k\) 应该满足在区间的相对位置不等于区间排名,容易证明第一个满足这样的 \(k\) 一定是排序后会被换到后面去的。
反过来思考,\(\forall j\in [i,k-1]\),\(a_j\) 都是区间 \([j,i+m-1]\) 的最小值,即 \(a_k\) 不是区间 \([k,i+m-1]\) 的最小值,那么这个就好做了,用单调栈预处理 \(r_i\),即 \(i\) 作为最小值能拓展到的最远位置,\(k\) 即为 \([i,i+m-1]\) 中第一个满足 \(r_k<i+m-1\) 的数,用 ST 表预处理 \(r_i\) 的区间最小值,然后二分即可。
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()
#define N 202507
#define M 19
// #define int long long
int n,m,a[N],st[N],r[N],tp,mn[N][M],LG[N];
inline void init(){
rep(i,1,n){
while(tp&&a[st[tp]]>a[i]){
r[st[tp]]=i-1;
tp--;
}
st[++tp]=i;
}
while(tp){
r[st[tp]]=n;
tp--;
}
LG[0]=-1;
rep(i,1,n){
LG[i]=LG[i>>1]+1;
mn[i][0]=r[i];
}
rep(j,1,18){
rep(i,1,n){
if(i+(1<<j)-1>n){
continue;
}
mn[i][j]=min(mn[i][j-1],mn[i+(1<<(j-1))][j-1]);
}
}
}
inline int ask(int l,int r){
int t=LG[r-l+1];
return min(mn[l][t],mn[r-(1<<t)+1][t]);
}
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
cin>>n>>m;
rep(i,1,n){
cin>>a[i];
}
init();
vector<pr>v;
rep(i,1,n){
int l=i,r=i+m-1,ans=1e9;
if(r>n){
break;
}
while(l<=r){
int mid=(l+r)>>1;
if(ask(i,mid)<i+m-1){
ans=mid;
r=mid-1;
}
else{
l=mid+1;
}
}
v.pb({i,ans});
}
sort(all(v),[](pr x,pr y){
if(x.se==y.se){
return x.fi<y.fi;
}
return x.se>y.se;
});
sort(a+v[0].fi,a+v[0].fi+m);
rep(i,1,n){
cout<<a[i]<<' ';
}
return 0;
}

浙公网安备 33010602011771号