[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;
}