544 字
3 分钟
Shop 题解
2025-06-03
544 字 · 3 分钟

shop

📝 NOTE 原题

题目描述

小 A 来到了一个商店,商店内有 件物品,每件物品有一个售价 ,小 A 是一个奸商,因此他能够把每件物品以 的价格卖出。

而由于小 A 背包空间有限,他只能买走恰好一件商品。而小 A 每次购买之后,小 B 将有可能将小 A 的物品摧毁,此时小 A 必须继续购买,并且商店不会返还购买这件物品的钱。小 B 至多可以摧毁 件物品。

小 A 的目标是最大化自己的收益。

小 B 的目标是最小化小 A 获得的收益,即卖出的商品所得减去购买所有物品的总花费。

注意到任何时刻小 B 都可以选择不将小 A 手中的物品摧毁,这样小 A 就必须立刻带着这件物品离开商店。

输入格式

第一行一个正整数 ,表示数据组数。

对于每组数据:

第一行两个正整数 ,分别表示物品数目和小 B 可摧毁的物品数量。

接下来 行,每行两个正整数 ,表示第 件物品的售价和小 A 能卖出的价格。

输出格式

对于每组数据,一行一个整数表示小 A 最终能获得的最大收益。由于小 A 可以直接走出商店(什么都不买),这个收益显然是非负的。

数据范围

这个问题看起来就很难以下手,因为它涉及到了两个人都要以最优策略进行,我们思考是否能对它进行转化,以方便我们进行处理。

而以下便是一种合理的转化方案:

为一个 的排列,小 A 需要找到最优的 ,使 最大。

这个东西仍然不好处理,我们似乎很难设计一个状态去达到这道题所要求的最优化状态。不过,有的时候如果最优化问题比较复杂,我们可以考虑一下是否能把它转为可行性问题来分析。尝试二分一个答案 ,则我们需要判断 是否可达,实际上,也就是要求在最优 下,有

不过就算如此,这个 还是很讨厌,研究我们是否有去掉 的方法。经过一些思考,我们可以得出关于 的一个结论:

我们可以通过反证法来证明这一结论,若 ,设 ,则我们求出的价值应为

若交换 ,价值变为

显然新价值无论如何都比旧价值大,通过简单的比较就可以得出,故无论如何,均有

所以我们先将商品按照从小到大排序,然后考虑顺着选择 ,使 。我们可以设 表示我们当前考虑到第 个物品,选了 个物品,且保证 下,最小的

将状态全部初始化为 ,令 ,则转移

时间复杂度 ,仍然无法通过。

如果再多思考一点,会发现它其实满足贪心的性质:假如我已知前 个物品中最多可以选 个满足 ,且使 最小,那么我们若能选第 个,必然满足 才可以。所以若可以选,我们则选。若不可以选,那么当 时,我们不妨交换最大值与 ,因为这样能使 最小,而且可以说明这样做可行性不会被破坏,用堆维护即可。

时间复杂度

代码


            
#include<bits/stdc++.h>

            
using namespace std;

            
#define int long long

            
#define pr pair<int,int>

            
#define fi first

            
#define se second

            
int n,m;

            
int const MAX=1e5+10;

            
pr a[MAX];

            
bool check(__int128 val){

            
    __int128 res=0;

            
    int cnt=0;

            
    priority_queue<int> Q;

            
    for(int i=1;i<=n;i++){

            
        if(a[i].se-a[i].fi-res>=val){

            
            res+=a[i].fi;

            
            cnt++;

            
            Q.push(a[i].fi);

            
        }else{

            
            if(!Q.empty()&&Q.top()>a[i].fi){

            
                res-=Q.top();

            
                res+=a[i].fi;

            
                Q.pop();

            
                Q.push(a[i].fi);

            
            }

            
        }

            
    }

            
    return cnt>m;

            
}

            
void solve(){

            
    cin>>n>>m;

            
    for(int i=1;i<=n;i++)cin>>a[i].fi>>a[i].se;

            
    sort(a+1,a+n+1,[](pr t1,pr t2){return t1.se<t2.se;});

            
    __int128 ans=0,l=0,r=1e18+1;

            
    while(l<=r){

            
        __int128 mid=(l+r)/2;

            
        if(check(mid)){

            
            ans=mid;

            
            l=mid+1;

            
        }else r=mid-1;

            
    }

            
    cout<<(long long)ans<<"\n";

            
}

            
signed main(){

            
    freopen("shop.in","r",stdin);

            
    freopen("shop.out","w",stdout);

            
    int T;

            
    cin>>T;

            
    while(T--)solve();

            
    return 0;

            
}

            
#include<bits/stdc++.h>

            
using namespace std;

            
#define int long long

            
#define pr pair<int,int>

            
#define fi first

            
#define se second

            
int n,m;

            
int const MAX=1e5+10;

            
pr a[MAX];

            
bool check(__int128 val){

            
    __int128 res=0;

            
    int cnt=0;

            
    priority_queue<int> Q;

            
    for(int i=1;i<=n;i++){

            
        if(a[i].se-a[i].fi-res>=val){

            
            res+=a[i].fi;

            
            cnt++;

            
            Q.push(a[i].fi);

            
        }else{

            
            if(!Q.empty()&&Q.top()>a[i].fi){

            
                res-=Q.top();

            
                res+=a[i].fi;

            
                Q.pop();

            
                Q.push(a[i].fi);

            
            }

            
        }

            
    }

            
    return cnt>m;

            
}

            
void solve(){

            
    cin>>n>>m;

            
    for(int i=1;i<=n;i++)cin>>a[i].fi>>a[i].se;

            
    sort(a+1,a+n+1,[](pr t1,pr t2){return t1.se<t2.se;});

            
    __int128 ans=0,l=0,r=1e18+1;

            
    while(l<=r){

            
        __int128 mid=(l+r)/2;

            
        if(check(mid)){

            
            ans=mid;

            
            l=mid+1;

            
        }else r=mid-1;

            
    }

            
    cout<<(long long)ans<<"\n";

            
}

            
signed main(){

            
    freopen("shop.in","r",stdin);

            
    freopen("shop.out","w",stdout);

            
    int T;

            
    cin>>T;

            
    while(T--)solve();

            
    return 0;

            
}

            
#include<bits/stdc++.h>

            
using namespace std;

            
#define int long long

            
#define pr pair<int,int>

            
#define fi first

            
#define se second

            
int n,m;

            
int const MAX=1e5+10;

            
pr a[MAX];

            
bool check(__int128 val){

            
    __int128 res=0;

            
    int cnt=0;

            
    priority_queue<int> Q;

            
    for(int i=1;i<=n;i++){

            
        if(a[i].se-a[i].fi-res>=val){

            
            res+=a[i].fi;

            
            cnt++;

            
            Q.push(a[i].fi);

            
        }else{

            
            if(!Q.empty()&&Q.top()>a[i].fi){

            
                res-=Q.top();

            
                res+=a[i].fi;

            
                Q.pop();

            
                Q.push(a[i].fi);

            
            }

            
        }

            
    }

            
    return cnt>m;

            
}

            
void solve(){

            
    cin>>n>>m;

            
    for(int i=1;i<=n;i++)cin>>a[i].fi>>a[i].se;

            
    sort(a+1,a+n+1,[](pr t1,pr t2){return t1.se<t2.se;});

            
    __int128 ans=0,l=0,r=1e18+1;

            
    while(l<=r){

            
        __int128 mid=(l+r)/2;

            
        if(check(mid)){

            
            ans=mid;

            
            l=mid+1;

            
        }else r=mid-1;

            
    }

            
    cout<<(long long)ans<<"\n";

            
}

            
signed main(){

            
    freopen("shop.in","r",stdin);

            
    freopen("shop.out","w",stdout);

            
    int T;

            
    cin>>T;

            
    while(T--)solve();

            
    return 0;

            
}

            
#include<bits/stdc++.h>

            
using namespace std;

            
#define int long long

            
#define pr pair<int,int>

            
#define fi first

            
#define se second

            
int n,m;

            
int const MAX=1e5+10;

            
pr a[MAX];

            
bool check(__int128 val){

            
    __int128 res=0;

            
    int cnt=0;

            
    priority_queue<int> Q;

            
    for(int i=1;i<=n;i++){

            
        if(a[i].se-a[i].fi-res>=val){

            
            res+=a[i].fi;

            
            cnt++;

            
            Q.push(a[i].fi);

            
        }else{

            
            if(!Q.empty()&&Q.top()>a[i].fi){

            
                res-=Q.top();

            
                res+=a[i].fi;

            
                Q.pop();

            
                Q.push(a[i].fi);

            
            }

            
        }

            
    }

            
    return cnt>m;

            
}

            
void solve(){

            
    cin>>n>>m;

            
    for(int i=1;i<=n;i++)cin>>a[i].fi>>a[i].se;

            
    sort(a+1,a+n+1,[](pr t1,pr t2){return t1.se<t2.se;});

            
    __int128 ans=0,l=0,r=1e18+1;

            
    while(l<=r){

            
        __int128 mid=(l+r)/2;

            
        if(check(mid)){

            
            ans=mid;

            
            l=mid+1;

            
        }else r=mid-1;

            
    }

            
    cout<<(long long)ans<<"\n";

            
}

            
signed main(){

            
    freopen("shop.in","r",stdin);

            
    freopen("shop.out","w",stdout);

            
    int T;

            
    cin>>T;

            
    while(T--)solve();

            
    return 0;

            
}
Shop 题解
https://blog.hanyblue.com/posts/solution/shop/
作者
hanyblue
发布于
2025-06-03
许可协议
CC BY-NC-SA 4.0