/*Bismillahir Rahmanir Rahim*///{
#include <bits/stdc++.h>
using namespace std;
using ll = long long; using ull = unsigned long long; using ld = long double;
const ll llinf = (1ll<<61)-1;
const double eps = 1e-6, ldeps = 1e-9;
struct Dbg {
static constexpr auto &os = cout;   // replace by cerr in interactive.
template<class C> static auto dud(C *x)->decltype(os << *x, 0);
template<class C> static char dud(...);
template<class C> typename enable_if<sizeof dud<C>(0)!=1, Dbg&>::type operator<<(const C &x) { os << x; return *this; }
template<class C> Dbg &dump(C b, C e) {
    *this << "\n[";
    int cur = 0;
    for (C i = b; i!=e and cur<26; i++, cur++) *this << ", "+2*(i==b) << *i;
    return *this << ']';
}
template<class C> typename enable_if<sizeof dud<C>(0)==1, Dbg&>::type operator<<(const C &x) {
    return dump(begin(x), end(x));
}
template<class C, size_t X> typename enable_if<!is_same<C, const char>::value, Dbg&>::type operator <<(C (&x)[X]) {
    return dump(begin(x), end(x));
}
template<class B, class C> Dbg &operator <<(const pair<B, C> &x) {
    return *this << '{' << x.first << ", " << x.second << '}';
}
template<class C, size_t Y> struct TP {
    void operator()(Dbg& os, const C &t) { TP<C, Y-1>()(os, t); os << ", " << get<Y-1>(t); }
};
template<class C> struct TP<C, 1> { void operator()(Dbg& os, const C &t) { os << get<0>(t); } };
template<class... C> Dbg& operator<<(const tuple<C...> &t) {
    os << '{', TP<decltype(t), sizeof...(C)>()(*this, t); return *this << '}';
}
Dbg &operator<<(ostream&(*x)(std::ostream&)) { os << x; return *this; }
} dbg;
void err(istringstream *iss) { delete iss; }
template<class C, class... Args> void err(istringstream *iss, const C &val, const Args &... args) {
    string name; *iss >> name; if (name.back()==',') name.pop_back();
    dbg << name << " = " << val << "; ", err(iss, args ...);
}
#define bug(args...) dbg << __LINE__ << ": ", err(new istringstream(string(#args)), args), dbg << endl
#define ASSERT(a, o, b) { if (!((a) o (b))) bug(a, b), assert((a) o (b)); }
#define sl(a) int(strlen(a))
#define sz(a) int(a.size())
int T, Q, cn;//}
const int inf = 1000000007, mxn = 2005;

template<class C> C compress(vector<C> &v) {//{//prefer using unique+function with lower_bound when compressing combined vectors
    int sz = sz(v);
    vector<pair<C, int> > tmp(sz);
    for (int i = 0; i < sz; i++) {
        tmp[i] = {v[i], i};
    }
    sort(begin(tmp), end(tmp));
    int cur = 1;
    for (int i = 0; i < sz; i++) {
        cur += i and tmp[i].first!=tmp[i-1].first;
        v[tmp[i].second] = cur;
    }
    return cur;
}//}

template <class T> class BIT//{
{
    vector<T> tree;
public:
    int N, mnIdx;
    BIT(int _n, int _mnIdx) : N(_n), mnIdx(_mnIdx) {   // mnIdx<actual & N>actual hole no problem
        tree.resize(N+2);
    }

    void reset() {fill_n(tree.begin(), N+2, 0);}

    void addAtIdx(int idx, T val) {idx+=1-mnIdx;
        while (idx<=N) tree[idx] += val, idx += (idx & -idx);
    }

    T prefixSum(int idx) {idx+=1-mnIdx;
        T sum = 0;
        while (idx>0) sum += tree[idx], idx -= (idx & -idx);
        return sum;
    }

    T rangeSum(int l, int r) {
        return prefixSum(r)-prefixSum(l-1);
    }

    void addRange(int l, int r, T val) { addAtIdx(l, val), addAtIdx(r+1, -val); }

    // upper_bound(x)==lower_bound(x+1) in non-fraction.
    int lower_bound(T x) { // returns mnIdx+N if no >= found
        int idx = 0, mask = 1<<(31^__builtin_clz(N)), ret = N+1, tIdx;
        while (mask) {
            tIdx = idx+mask, mask >>= 1;
            if (tIdx>=N || tIdx<=0) continue;
            if (tree[tIdx]>=x) ret = min(ret, tIdx); else idx = tIdx, x -= tree[tIdx];
        }ret-=1-mnIdx;
        return ret;
    }

    void multiplyAll(T c) {   // to divide all replace * by /
        for (int i = 1; i <= N; i++) tree[i] *= c;
    }
};//}
BIT<int> ft(mxn, 0);

int n, K, a[mxn], uncompress[mxn];
vector<int> pos[mxn];

bool check(int l, int r, vector<int> &v) {
    int o = -1;
    vector<int> lm(n), rm(n);
    for (int i = 0; i < n; i++) {
        if (v[i]<l) o = i;
        lm[i] = o;
    }
    o = n;
    for (int i = n-1; i >= 0; i--) {
        if (v[i]<l) o = i;
        rm[i] = o;
    }
    ft.reset();
    int op = 0;
    for (int i = l; i <= r; i++) {
        for (auto &j : pos[i]) {
            if (rm[j]-lm[j]-1-ft.prefixSum(j)>=K) op++, ft.addRange(lm[j]+1, rm[j]-1, 1);
        }
    }
    return op>=Q;
}

signed main() { ios::sync_with_stdio(0); cin.tie(NULL); cout.precision(11);

/*Easy to recognize two pointers after compressing the array to check validity of a range, we can use nlogn with BIT:
Consider the range [2, 3] in 1332331 where K==3, we can delete a 2 and any two 3.
==> We need to precalculate first occurence to left and right of an element < l. Then we need range update, point query.*/

    cin >> n >> K >> Q;
    vector<int> v(n);
    for (int i = 1; i <= n; i++) {
        cin >> a[i], v[i-1] = a[i];
    }
    int cnt = compress(v);

    for (int i = 0; i < n; i++) {
        uncompress[v[i]] = a[i+1];
        pos[v[i]].push_back(i);
    }

    int mn = inf;
    for (int i = 1, j = 0; i<=cnt and j<=cnt; ) {
        if (check(i, j, v)) mn = min(mn, uncompress[j]-uncompress[i]), i++;
        else j++;
    }
    cout << mn << '\n';
}

Measured memory_bytes: 384