[ARC098E] Range Minimum Queries

考虑枚举 $Y$。

根据 $Y$ 的定义,有:序列中比 $Y$ 小的数都不能被选到长为 $K$ 的区间内。所以我们不妨用那些 $<Y$ 的数把序列分割成几个连续段去处理。

有了连续段的性质之后,我们暴力处理出每个元素所处的连续段以及连续段的长度。之后再从小到大枚举 $X$,每次看看所有 $A_i=X$ 的 $i$ 所在的连续段长度是否 $\geq k$。假若是,说明这里可以贡献一个长为 $k$ 的区间,同时把 $X$ 从序列中删去(注:这里不需要真正的删去,只要把其所在连续段长度 $-1$ 即可),否则无事发生。

假若记 $Y=i$ 时,最小的 $X$ 为 $x_i$。那么答案就是 $\min_{i=1}^n x_i-i$。

#include <bits/stdc++.h>
#define FL(i, a, b) for(int i = (a); i <= (b); i++)
#define FR(i, a, b) for(int i = (a); i >= (b); i--)
using namespace std;
const int N = 2010;
int n, k, q, r, tot, cnt, ans = 1e9;
int a[N], id[N], rk[N], d[N], len[N];
int cmp(int i, int j){return a[i] < a[j];}
int main(){
    scanf("%d%d%d", &n, &k, &q);
    FL(i, 1, n) scanf("%d", &a[id[i] = i]);
    sort(id + 1, id + n + 1, cmp);
    FL(i, 1, n) rk[id[i]] = i;
    FL(i, 1, n){
        cnt = tot = 0, fill(d + 1, d + n + 1, 0);
        FL(j, 1, n) if(rk[j] >= i){
            if(j == 1 || rk[j - 1] < i) len[++tot] = 0;
            len[d[j] = tot]++;
        }
        for(r = i; r <= n && cnt < q; r++){
            cnt += (len[d[id[r]]]-- >= k);
        }
        if(cnt < q) break; ans = min(ans, a[id[r - 1]] - a[id[i]]);
    }
    printf("%d\n", ans);
    return 0;
}
posted @ 2023-08-22 15:37  徐子洋  阅读(34)  评论(0)    收藏  举报  来源