1 条题解

  • 0
    @ 2025-12-11 20:47:31

    题目分析

    本题要求从一个未知的单调递增序列中,选择 KK 个数,使得它们的和在 [A,2A][A, 2A] 范围内。我们最多只能查询 SS 个元素的值。这是一个典型的交互式选择问题,需要在有限的查询次数内找到满足条件的解。

    关键观察

    1. 序列的单调性: 序列 xx 是单调递增的,即 x1<x2<<xNx_1 < x_2 < \dots < x_N。这一性质是关键,允许我们进行二分搜索和范围推断。

    2. 条件限制:

    需要选择恰好 KK 个数

    和必须在 [A,2A][A, 2A] 范围内

    最多查询 SS 个元素的值

    1. 贪心策略:

    最小的可能和:选择前 KK 个数 x1,x2,,xKx_1, x_2, \dots, x_K

    最大的可能和:选择后 KK 个数 xNK+1,,xNx_{N-K+1}, \dots, x_N

    如果最小和已经大于 2A2A 或最大和小于 AA,则无解

    算法思路

    1. 初步检查与处理

    算法首先查询前 KK 个元素:

    如果这 KK 个数的和已经在 [A,2A][A, 2A] 范围内,直接返回答案

    如果第 KK 个元素 xKAx_K \ge A,那么最小的 KK 个元素之和至少为 KxKKAK \cdot x_K \ge K \cdot A,当 K2K \ge 2 时可能超过 2A2A,需要进一步检查

    1. 二分搜索关键位置

    通过二分搜索找到第一个大于 AA 的元素位置:

    int l = K + 1, r = N + 1;
    while (l < r) {
        int mid = l + r >> 1;
        if (skim(mid) > A) r = mid;
        else l = mid + 1;
    }
    

    这个位置记为 rr,满足 xr>Ax_r > Axr1Ax_{r-1} \le A(如果存在)。

    1. 替换策略

    情况 1: 用第 rr 个元素替换第 KK 个元素

    新的和为:(x1++xK1)+xr(x_1 + \dots + x_{K-1}) + x_r

    由于 xr>Ax_r > A,而前 K1K-1 个元素的和较小,总和可能在 [A,2A][A, 2A]

    检查条件:如果 sumxK+xr2A\text{sum} - x_K + x_r \le 2A,则成功

    情况 2: 滑动窗口替换

    如果情况 1 不满足,尝试用后面的元素替换前面的多个元素:

    从位置 i=r1i = r-1 开始,向前尝试最多 KK 个位置

    每次用 xix_i 替换掉当前集合中最小的元素

    随着替换的进行,总和逐渐增大

    当总和首次达到 A\ge A 时,检查是否 2A\le 2A

    正确性证明

    1. 单调性的利用:

    序列单调递增,因此替换较大元素会增大总和

    二分搜索正确找到第一个大于 AA 的元素

    1. 替换策略的正确性:

    情况 1:用一个大元素 xr(>A)x_r (>A) 替换 xKx_K,可能使总和进入目标区间

    情况 2:逐步替换,总和单调递增。由于序列递增,每次替换都会增加总和

    1. 边界情况处理:

    如果 xKAx_K \ge A 且前 KK 个元素和超过 2A2A,则可能无解

    如果所有元素都太小,无法达到 AA,则无解

    1. 查询次数控制:

    最多查询 KK(前 KK 个)+ 1(二分搜索)+ KK(滑动窗口)= 2K+12K+1

    由于 K10K \le 10,最多 21 次查询,远小于 SSS105S \le 10^5

    时间复杂度

    • 查询次数:O(K)O(K),最多约 2K+12K+1

    • 计算复杂度:O(K)O(K)

    • 总复杂度:O(K)O(K),非常高效

    AC代码

    #include <bits/stdc++.h>
    #include "books.h"
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef vector<int> vec;
    const int N = 1e5 + 10;
    ll x[N], sum;
    void solve(int N, int K, ll A, int S) {
        vec ans;
    
        for (int i = 1; i <= K; i ++) {
            sum += (x[i] = skim(i));
            ans.pb(i);
        }
    
        if (sum >= A && sum <= A * 2)
            answer(ans);
    
        if (x[K] >= A)
            impossible();
    
        int l = K + 1, r = N + 1;
    
        while (l < r) {
            int mid = l + r >> 1;
    
            if (skim(mid) > A)
                r = mid;
            else
                l = mid + 1;
        }
    
        if (r <= N && sum - x[K] + skim(r) <= 2 * A) {
            ans.pop_back();
            ans.pb(r);
            answer(ans);
        }
    
        for (int i = l - 1; i >= max(l - K, K + 1); i --) {
            sum += skim(i) - x[l - i];
            ans.erase(ans.begin()), ans.pb(i);
    
            if (sum >= A)
                answer(ans);
        }
    
        impossible();
    }
    
    
    • 1

    信息

    ID
    6125
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    5
    已通过
    1
    上传者