1 条题解

  • 7
    @ 2026-9-15 16:45:54

    因为总伤害固定,免除的伤害越多,实际受到的伤害就越少。易得,将药水用于最大的 kk 场战斗上是最优的。

    所以对于任意一个前缀,我们只需要选出其中伤害最大的至多 kk 个敌人,用药水免除它们的伤害。

    具体地,从左到右遍历每个敌人,维护一个总伤害 sum,以及一个小根堆,堆里存当前选中的、准备用药水免除的伤害值,堆的大小不超过 kk。同时用 heal 记录堆中元素的总和(即免除的总伤害)。

    对于每个敌人 aia_i:

    • 把 aia_i 加入总伤害 sum。
    • 如果堆的大小小于 kk,直接放入堆,heal += a_i。
    • 否则,如果 aia_i 比堆顶(当前免除的最小伤害)大,就弹出堆顶,放入 aia_i,并更新 heal。
    • 然后检查实际受到的伤害 sum - heal。如果它 ≥m\ge m,说明傻鹿会在第 ii 个敌人处倒下,最多只能击败前 i−1i-1 个,输出 i-1 并结束。
    • 如果遍历完所有敌人都没有倒下,输出 n。

    时间复杂度:每组数据 O(nlog⁡k)O(n \log k),总 O(Tnlog⁡k)O(T n \log k),可以通过。

    参考代码:

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    
    const int N=1e5+5;
    
    ll n,m,k;
    ll a[N];
    
    void solve(){
        cin>>n>>m>>k;
        for(int i=1;i<=n;i++) cin>>a[i];
    
        priority_queue<ll,vector<ll>,greater<ll>> q; 
        ll sum=0,heal=0;
        for(int i=1;i<=n;i++){
            sum+=a[i];
    
            if(k>0){
                if(q.size()<k){
                heal+=a[i];
                q.push(a[i]);
                }else if(a[i]>q.top()){
                    heal-=q.top();
                    q.pop();
                    q.push(a[i]);
                    heal+=a[i];
                }
            }
            if(sum-heal>=m){
                cout<<i-1<<'\n';
                return;
            }
        }
        cout<<n<<'\n';
        return;
    }
    
    int main(){
        int T;cin>>T;
        while(T--) solve();
    }
    

    信息

    ID
    2738
    时间
    1000ms
    内存
    256MiB
    难度
    4
    标签
    (无)
    递交数
    19
    已通过
    12
    上传者