#54973: 本題解題報告


321qwedsa000@gmail.com (灝)


#include <cstdio>
#include <climits>
#include <cstring>

// ===== TMP: 編譯期常數 =====
// 二分最大迭代次數(log2(2e9) ≈ 31),用於編譯期展開
template<int N> struct Log2 {
    static constexpr int value = 1 + Log2<N/2>::value;
};
template<> struct Log2<1> { static constexpr int value = 0; };
template<> struct Log2<0> { static constexpr int value = 0; };

constexpr int MAX_ITERS = Log2<2000000001>::value + 1; // = 32,編譯期確定

// ===== TMP: I/O 策略 — 大型輸入緩衝區 =====
// 一次性將整個 stdin 讀入記憶體緩衝區,之後完全不做 syscall
// 緩衝區大小:N=10^6,每個數最多 11 chars + 空白 = ~12 MB
// 但題目記憶體限制 5 MB!
// → 改用分塊緩衝:固定 512 KB 緩衝,循環讀入
// → 搭配「記錄每個數的檔案偏移」是不可行的(偏移陣列本身就 4 MB)
// → 最佳方案:緩衝讀入 + rewind,每次掃描時重填緩衝

namespace FastIO {
    constexpr int BUF_SIZE = 1 << 19; // 512 KB,遠小於 5 MB
    static char buf[BUF_SIZE];
    static int  buf_pos = 0;
    static int  buf_len = 0;

    inline void reset() {
        rewind(stdin);
        buf_pos = buf_len = 0;
    }

    inline int gc() {
        if (buf_pos == buf_len) {
            buf_len = (int)fread(buf, 1, BUF_SIZE, stdin);
            buf_pos = 0;
            if (buf_len == 0) return EOF;
        }
        return (unsigned char)buf[buf_pos++];
    }

    template<typename T>
    inline T readInt() {
        T x = 0; bool neg = false; int c = gc();
        while (c != '-' && (c < '0' || c > '9')) c = gc();
        if (c == '-') { neg = true; c = gc(); }
        while (c >= '0' && c <= '9') { x = x * 10 + (c - '0'); c = gc(); }
        return neg ? -x : x;
    }

    inline void writeInt(int x) {
        if (x < 0) { putchar_unlocked('-'); x = -x; }
        if (x == 0) { putchar_unlocked('0'); putchar_unlocked('\n'); return; }
        char out[12]; int len = 0;
        while (x > 0) { out[len++] = '0' + x % 10; x /= 10; }
        for (int i = len - 1; i >= 0; i--) putchar_unlocked(out[i]);
        putchar_unlocked('\n');
    }
}

// ===== TMP: 掃描結果型別 =====
struct ScanResult {
    int gt;   // 嚴格 > threshold
    int eq;   // == threshold
    int vmin; // 本次掃描最小值(僅首次需要)
    int vmax; // 本次掃描最大值(僅首次需要)
};

// ===== TMP: 編譯期展開的掃描器 =====
// 利用 SIMD-friendly 寫法,4 路並行累加,減少 branch misprediction
template<bool NeedRange>
inline ScanResult scanOnce(int n, int threshold) {
    ScanResult r = {0, 0, INT_MAX, INT_MIN};
    // 4 路展開:減少迴圈控制開銷
    int gt0=0, gt1=0, gt2=0, gt3=0;
    int eq0=0, eq1=0, eq2=0, eq3=0;
    int vmin = INT_MAX, vmax = INT_MIN;

    int i = 0;
    const int n4 = n & ~3; // n 向下對齊到 4 的倍數

    for (; i < n4; i += 4) {
        int v0 = FastIO::readInt<int>();
        int v1 = FastIO::readInt<int>();
        int v2 = FastIO::readInt<int>();
        int v3 = FastIO::readInt<int>();

        gt0 += (v0 > threshold);
        gt1 += (v1 > threshold);
        gt2 += (v2 > threshold);
        gt3 += (v3 > threshold);

        eq0 += (v0 == threshold);
        eq1 += (v1 == threshold);
        eq2 += (v2 == threshold);
        eq3 += (v3 == threshold);

        if constexpr (NeedRange) {
            if (v0 < vmin) vmin = v0; if (v0 > vmax) vmax = v0;
            if (v1 < vmin) vmin = v1; if (v1 > vmax) vmax = v1;
            if (v2 < vmin) vmin = v2; if (v2 > vmax) vmax = v2;
            if (v3 < vmin) vmin = v3; if (v3 > vmax) vmax = v3;
        }
    }
    // 尾端處理
    for (; i < n; i++) {
        int v = FastIO::readInt<int>();
        gt0 += (v > threshold);
        eq0 += (v == threshold);
        if constexpr (NeedRange) {
            if (v < vmin) vmin = v;
            if (v > vmax) vmax = v;
        }
    }

    r.gt   = gt0 + gt1 + gt2 + gt3;
    r.eq   = eq0 + eq1 + eq2 + eq3;
    r.vmin = vmin;
    r.vmax = vmax;
    return r;
}

// ===== TMP: 演算法優化 — 減少掃描次數 =====
// 原版每輪二分都重讀 stdin(rewind + fread),共 ~31 次
// 優化:首次掃描同時取得 vmin/vmax 和 k
//       縮小二分邊界後,利用「上一輪 gt/eq 結果」更新 lo/hi
//       不需每輪都重讀第一行(n)— 記錄偏移並直接 fseek 到數列起點

// 記錄數列在檔案中的起始偏移(位元組)
// 這樣 rewind 後只需跳過第一行而不重新解析
struct FileLayout {
    long data_offset; // 數列第一個數字的 byte 偏移
    int  n;
    int  k;
};

inline FileLayout readHeader() {
    FastIO::reset();
    int n = FastIO::readInt<int>();
    // 記錄當前位置:數列起點 = 目前 ftell 的近似值
    // 由於用了緩衝區,ftell 不準確;改用「讀完數列後記錄 k 的位置」的方式
    // 實作:直接記下 buf_pos(緩衝內偏移)和已讀的 fread 塊數
    // 簡化方案:首次掃描順便取得 vmin/vmax,之後 fseek 到 data_offset
    long data_offset = ftell(stdin) - (FastIO::buf_len - FastIO::buf_pos);
    return {data_offset, n, 0};
}

// ===== CRTP Solver =====
template<typename Derived>
struct SolverBase { void run() { static_cast<Derived*>(this)->solve(); } };

struct KthSolver : SolverBase<KthSolver> {

    void solve() {
        // --- 步驟一:首次掃描,取得 vmin/vmax ---
        FastIO::reset();
        int n = FastIO::readInt<int>();

        // 記錄數列起點的檔案偏移(緩衝區讀完第一行之後)
        // buf_pos 指向緩衝區內第二行第一個字元
        // 實際檔案偏移 = 已讀的 fread 總量 - 緩衝區剩餘量
        // 為求正確,直接記錄 stdin 的 ftell
        long data_start = ftell(stdin) - (long)(FastIO::buf_len - FastIO::buf_pos);

        // 首次掃描:取 vmin, vmax(threshold 設 INT_MAX,gt 永遠 = 0)
        ScanResult first = scanOnce<true>(n, INT_MAX);

        int k = FastIO::readInt<int>();

        long long lo = first.vmin, hi = first.vmax;
        int ans = first.vmax;

        // --- 步驟二:二分答案,每輪 fseek 直接跳到數列起點 ---
        // 比 rewind + 重讀 n 節省 ~解析第一行 的時間(雖然小但乾淨)
        // 編譯期確定最大迭代數(MAX_ITERS = 32),可展開或提示編譯器
        for (int iter = 0; iter < MAX_ITERS && lo <= hi; ++iter) {
            long long mid = lo + (hi - lo) / 2;

            // fseek 到數列起點,重置緩衝
            fseek(stdin, data_start, SEEK_SET);
            FastIO::buf_pos = FastIO::buf_len = 0; // 清空緩衝,強制重填

            ScanResult r = scanOnce<false>(n, (int)mid);

            if (r.gt >= k) {
                lo = mid + 1;
            } else if (r.gt + r.eq >= k) {
                ans = (int)mid;
                break;
            } else {
                hi = mid - 1;
            }
        }

        FastIO::writeInt(ans);
    }
};

int main() {
    KthSolver solver;
    solver.run();
    return 0;
}