购买

题目传送门

这个题目有一点坑

我当时一眼以为是DP(本人DP不太擅长)

正解

我们可以按照b从从小到大排序
然后我们就先选前\(k\)个,因为b已经排好序了,所以\(b_k\)就是答案,然后记一个sum表示当前选的物品总和是多少。还有一个ans,每轮实时更新答案并记录
然后对于\(i=k,k+1,k+2,...,n\),我们可以去看当前的\(a_i\)有没有比前\(k\)个里面的最大值来的小。如果是的话,那么sum就更新,然后在加上\(b_i\),最后ans取min

那么这个时候,我们的时间复杂度是(T太小了,就不考虑了)O(k²n),不能通过。
这个时候,我们想到了———

那么我们就可以O(1)的求出最小值了,但是插入操作是log的,但是还是可以通过。

最终,时间复杂度是O(nklogk)

代码如下

#include<bits/stdc++.h>
using namespace std;

#define ll long long

int n,k;
struct info{
    ll a,b;
}p[1000001];

bool cmp(info A,info B){
    return A.b<B.b;
}

void solve(){
    
    cin>>n>>k;
    for(int i=1;i<=n;i++) cin>>p[i].a;
    for(int i=1;i<=n;i++) cin>>p[i].b;
    sort(p+1,p+n+1,cmp);
    priority_queue<ll> pq;
    ll ans=0,sum=0;
    for(int i=1;i<=k;i++){
        pq.push(p[i].a);
        sum+=p[i].a;
    }
    ans=sum+p[k].b;
    for(int i=k+1;i<=n;i++){
        if(!pq.empty()&&p[i].a<pq.top()){
            sum-=pq.top();
            pq.pop();
            pq.push(p[i].a);
            sum+=p[i].a;
        }
        ans=min(ans,sum+p[i].b);
    }
    cout<<ans<<endl;
}

int main(){
    cin.tie(0)->sync_with_stdio(0);
    freopen("buy.in","r",stdin);
    freopen("buy.out","w",stdout);
    int t;
    cin>>t;
    while(t--) solve();
}

注意!

1.注意爆int
2.pq默认的是小根堆,然后最大值在顶端
3.对应的,大根堆是最小值在顶端,如下写法

priority_queue<T,vector<T>,greater<T> >

在某些语法中,最后两个尖括号要分开,不然会判断成流,然后报错!

posted @ 2026-01-24 12:04  zhangruotian_Max  阅读(1)  评论(0)    收藏  举报