题解:P1752 点菜

## 思路:
### 单调性:
显然的,当 $k$ 越大,吃完菜的可能是越大的。
### 贪心:
将题目拆解成子问题。

根据题意归纳可得,你一定需要让挑剔的人在保证美味度的情况下,尽可能的吃贵的菜,让贫穷的人在保证价格的情况下尽可能吃美味度小的菜(其实随便吃就行,不影响),可以用优先队列进行维护。

将挑剔的人从大到小排序后,可以保证上一个人可以吃的菜,这一个人也一定能吃,然后尽可能吃 $k$ 周贵的。

将贫穷的人从小到大排序后,可以保证上一个人可以吃的菜,这一个人也一定能吃,然后尽可能吃 $k$ 周美味度小的的。
### 时间复杂度:

$\mathcal{O(n\log^2{n})}$。
## code:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXM=200005,MAXN=50005;
int n,l1,l2,m,b[MAXN],c[MAXN];
struct node{
    int w,v;
    bool operator <(const node &x)const{
        return v<x.v;
    }
}a[MAXN<<2],sf[MAXN<<2];
priority_queue <node> q;
bool cmp(node a,node b){
    return a.w>b.w;
}
bool check(int k){
    if((n-l1-l2)*k>=m){
        return 1;
    }
    while(!q.empty()){
        q.pop();
    }
    int tot=1;
    for(int i=1;i<=l1;i++){
        while(tot<=m && a[tot].w>=b[i]){
            q.push(a[tot++]);
        }
        for(int j=1;j<=k && !q.empty();j++){
            q.pop();
        }
    } 
    int cnt=0;
    while(!q.empty()){
        sf[++cnt]=q.top();
        q.pop();
    }
    for(int i=tot;i<=m;i++){
        sf[++cnt]=a[i];
    }
    sort(sf+1,sf+cnt+1);
    tot=1;
    for(int i=1;i<=l2;i++){
        while(tot<=m && sf[tot].v<=c[i]){
            q.push(sf[tot++]);
        }
        for(int j=1;j<=k && !q.empty();j++){
            q.pop();
        }
    }
    int r=q.size()+cnt-tot+1;
    return r<=(n-l1-l2)*k;
}
signed main(){
    cin>>n>>m>>l1>>l2;
    for(int i=1;i<=m;i++){
        cin>>a[i].w>>a[i].v;
    }
    sort(a+1,a+m+1,cmp);
    for(int i=1;i<=l1;i++){
        cin>>b[i];
    }
    sort(b+1,b+l1+1);
    reverse(b+1,b+l1+1);
    for(int i=1;i<=l2;i++){
        cin>>c[i];
    }
    sort(c+1,c+l2+1);
    int l=1,r=m,ans=-1;
    while(l<=r){
        int mid=(l+r)>>1;
        if(check(mid)){
            ans=mid;
            r=mid-1;
        }else{
            l=mid+1;
        }
    }
    cout<<ans;
    return 0;
} 

题目列表 User Avatar 主页 题库 网校 训练题单 比赛 评测记录 讨论区 文章广场 更多功能 图片上传 云剪贴板 主题商店 咕值排名 等级分排名 洛谷有题 工单/反馈 相关链接 帮助中心 联系我们 社区规则 陶片放逐 管理名单 tttyy01 个人中心 用户设置 练习情况 我的题库 我的专栏 收藏夹 我的工单 锁定登出 P1164 小A点菜 提交答案加入题单复制题目 提交 230.52k 通过 110.78k 时间限制 1.00s 内存限制 512.00MB 题目编号 P1164 提供者 洛谷 难度 普及− 历史分数 暂无 提交记录 查看题解 题目反馈 标签 洛谷原创 相关讨论进入讨论版 推荐题目 复制 Markdown 中文 进入 IDE 模式 题目背景 uim 神犇拿到了 uoi 的 ra(镭牌)后,立刻拉着基友小 A 到了一家……餐馆,很低端的那种。 uim 指着墙上的价目表(太低级了没有菜单),说:“随便点”。 题目描述 不过 uim 由于买了一些书,口袋里只剩 M 元 (0<M≤10000)。 餐馆虽低端,但是菜品种类不少,有 N 种 (1≤N≤100),第 i 种卖 a i ​ 元 (0<a i ​ ≤1000)。由于是很低端的餐馆,所以每种菜只有一份。 小 A 奉行“不把钱吃光不罢休”的原则,所以他点单一定刚好把 uim 身上所有钱花完。他想知道有多少种点菜方法。 由于小 A 肚子太饿,所以最多只能等待 1 秒。 输入格式 第一行两个整数 N 和 M,分别表示菜品种类和 uim 身上的钱数。 第二行 N 个正整数 a i ​ (可能有重复),用空格隔开,分别表示每种菜的价格。 输出格式 一个正整数,表示点菜方案数,保证答案的范围在 [0,2 31 −1] 之内(不超过 C/C++的 int 范围)。 输入输出样例 输入 #1复制 4 4 1 1 2 2 输出 #1复制 3 说明/提示 2020.8.29,增添一组 hack 数据 by @yummy 加入题单 操作 加入做题计划 加入个人题单 加入团队题单 保存 复制题目 目标团队 获取团队中... 保存
11-24
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值