【题解】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;
}
posted @ 2025-07-09 11:57  Lucyna_Kushinada  阅读(10)  评论(0)    收藏  举报