前言

蒟弱本来是在亿万年前做二分答案专题栅栏的,由于数据水所以过掉了,后来发现有一个数据加强版,也就是本题,于是爆T了...过了有个五六个月回来填坑了...现在开O2是在最优解第一个(自豪ing

题目描述

有 \(n\) 块 大小分别为 \(a_i\) 的蛋糕,分给 \(m\) 个嘴大小分别为 \(b_i\) 的人,但是蛋糕只能以整块的形式给人,求最多给多少人。

思路

很明显,答案在排序之后具有单调性,所以可以二分能够分给多少人,但二分并没有一个明确的套路切蛋糕,所以需要进行深搜;

于是来考虑最优贪心策略:

  1. 首先将所有蛋糕和嘴的大小排序,优先喂嘴小的人;

对应着这两行:

n=read();F(i,1,n)a[i]=read(),tot+=a[i];std::sort(a+1,a+n+1);
m=read();F(i,1,m)b[i]=read();std::sort(b+1,b+m+1);
  1. 排完序后,考虑缩小二分范围,我们从小到大求得嘴大小的前缀和,如果到第 \(i\) 个人的嘴大小总和 \(pre_i\) 超过了上面求出的蛋糕大小总和 \(tot\),或者 \(b_i>a[n]\),那么到这里无论如何切都无法满足条件,二分的最大边界就是 \(i-1\) 了。另外,如果蛋糕总和都比最小的嘴小,那么一个也不能满足。

对应着这三行:

if(tot<b[1]){pi(0);return 0;}
F(i,1,m){pre[i]=pre[i-1]+b[i];if(pre[i]>tot||b[i]>a[n]){cnt=i-1;break;}}
if(!cnt)cnt=m;

我们开始二分+深搜:

  1. 在深搜过程中,枚举能够切下够这口嘴吃的蛋糕,切掉后蛋糕总大小要减去嘴的大小。如果这块蛋糕切剩下的不够最小嘴的,那么就相当于这块蛋糕没有用了,蛋糕总大小要再减去没有用的这部分。

也就是这样:

if(a[i]>=b[x]){
a[i]-=b[x];tot-=b[x];
if(a[i]<b[1])tot-=a[i];
}
  1. 显然,当剩下几张嘴的总大小比剩下几块蛋糕的总大小还要大时,方案是不符合的。

也就是这句:

if(pre[x]>tot)return 0;
  1. 当当前搜索到的这口嘴与下一个要搜索的嘴大小相同时,既然已经枚举到了第 \(i\) 块蛋糕,说明第 \(i\) 块蛋糕之前的蛋糕对于这个大小的嘴都是没有正确方案的,于是搜索下一口嘴时就可以直接从第 \(i\) 块蛋糕枚举。

这句话的实现长这样:

if(b[x]==b[x-1])fl=check(x-1,i);else fl=check(x-1,1);

最后无论有没有正确方案都要记得回溯啊!

if(a[i]<b[1])tot+=a[i];
a[i]+=b[x];tot+=b[x];

到最后如果枚举完所有的蛋糕都没有正确方案,就可以直接 \(return\ 0\) 了。

于是本题就可以愉快的结束了~

CODE

#include<cstring>
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
namespace EMT{
#define pf printf
#define F(i,a,b) for(register int i=a;i<=b;i++)
#define D(i,a,b) for(register int i=a;i>=b;i--)
inline int read(){int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();return x*f;}
inline void pi(int x){pf("%d",x);}inline void pn(){pf("\n");}inline void ps(int a[],int size){F(i,1,size)pi(a[i]);pn();}
int n,m,a[55],b[1100],ans,cnt,ws,tot,pre[1100];
inline bool check(int x,int st){
if(!x)return 1;
if(pre[x]>tot)return 0;
bool fl=0;
F(i,st,n){
if(a[i]>=b[x]){
a[i]-=b[x];tot-=b[x];
if(a[i]<b[1])tot-=a[i];
if(b[x]==b[x-1])fl=check(x-1,i);else fl=check(x-1,1);
if(a[i]<b[1])tot+=a[i];
a[i]+=b[x];tot+=b[x];
if(fl)return 1;
}
}return 0;
}
inline short main(){
n=read();F(i,1,n)a[i]=read(),tot+=a[i];std::sort(a+1,a+n+1);
m=read();F(i,1,m)b[i]=read();std::sort(b+1,b+m+1);;;;;;
if(tot<b[1]){pi(0);return 0;}
F(i,1,m){pre[i]=pre[i-1]+b[i];if(pre[i]>tot||b[i]>a[n]){cnt=i-1;break;}}
if(!cnt)cnt=m;
int l=1,r=cnt,ans=0;
while(l<=r){
int mid=(l+r)>>1;
if(check(mid,1))l=mid+1,ans=mid;
else r=mid-1;
}
pi(ans);
return 0;
}
}
signed main(){return EMT::main();}

luoguP1528&2329 栅栏&切蛋糕的更多相关文章

  1. 洛谷P1528 切蛋糕 [搜索,二分答案]

    题目传送门 切蛋糕 题目描述 Facer今天买了n块蛋糕,不料被信息组中球球等好吃懒做的家伙发现了,没办法,只好浪费一点来填他们的嘴巴.他答应给每个人留一口,然后量了量每个人口的大小.Facer有把刀 ...

  2. [洛谷P1528] 切蛋糕

    洛谷题目链接:切蛋糕 题目描述 Facer今天买了n块蛋糕,不料被信息组中球球等好吃懒做的家伙发现了,没办法,只好浪费一点来填他们的嘴巴.他答应给每个人留一口,然后量了量每个人口的大小.Facer有把 ...

  3. 刷题总结——切蛋糕(ssoj)

    题目: 切蛋糕 (cake.cpp/c/pas) [问题描述] BG 有一块细长的蛋糕,长度为�. 有一些人要来BG 家里吃蛋糕, BG把蛋糕切成了若干块(整数长度),然后分给这些人.为了公平,每个人 ...

  4. LRJ入门经典-0903切蛋糕305

    原题 LRJ入门经典-0903切蛋糕305 难度级别:B: 运行时间限制:1000ms: 运行空间限制:256000KB: 代码长度限制:2000000B 试题描述 如图所示有一个矩形蛋糕,上面划分成 ...

  5. 洛谷 P1714 切蛋糕 题解

    P1714 切蛋糕 题目描述 今天是小Z的生日,同学们为他带来了一块蛋糕.这块蛋糕是一个长方体,被用不同色彩分成了N个相同的小块,每小块都有对应的幸运值. 小Z作为寿星,自然希望吃到的第一块蛋糕的幸运 ...

  6. TZOJ 3042 切蛋糕(并查集)

    描述 KK是个心灵手巧的好姑娘,她做了一个大蛋糕请她的好朋友们来品尝.这个蛋糕分成n×n个正方形小格,每个小格包含一块水果.KK要把蛋糕切成若干块,显然她不会破坏任意一个小格.无聊的某同学在她切蛋糕时 ...

  7. 切蛋糕(贪心 or 优先队列)

    链接:https://www.nowcoder.com/acm/contest/80/D来源:牛客网 最可爱的applese生日啦,他准备了许多个质量不同的蛋糕,想请一些同学来参加他的派对为他庆生,为 ...

  8. HDOJ 1722--Cake(切蛋糕问题)

    一次生日Party可能有p人或者q人参加,现准备有一个大蛋糕.问最少要将蛋糕切成多少块(每块大小不一定相等),才能使p人或者q人出席的任何一种情况,都能平均将蛋糕分食. Input 每行有两个数p和q ...

  9. 单调队列练习题解(切蛋糕&好消息,坏消息)

    单调队列的练习题解 前言: 在上一篇学习记录中,单调队列给出了几道练习题,因为这两道题的算法以及思路相差无几(几乎可以算是双倍经验quq),所以就在这里集中写一下相关的题解 前置知识: 见:队列专题( ...

随机推荐

  1. WPF技巧:命中测试在视觉树中的使用

    我们有时候又需求从当前视觉树中找一些东西,比如鼠标按下的时候,看看鼠标下的元素都有什么.又比如某块区域下有哪些元素?某个坐标点下有哪些元素? 这些需求在使用 命中测试的时候,可以非常方便和快速的去找到 ...

  2. kong配置upstream实现简单的负载均衡

    目录 通过konga实现 1. 配置upstream 2. 配置Service发布 3. 配置Route,匹配规则 4. 验证结果 通过 Kong Admin API实现 1. 配置upstream ...

  3. 技能篇:docker的简易教程

    虚拟机技术每家公司发展到一定规模都必须考虑的,更好的环境隔离,更好的事故排查,更好的服务部署 docker的原理 docker更换阿里源 docker容器的相关命令 Dockerfile文件编写 do ...

  4. 【Git】pull遇到错误:error: Your local changes to the following files would be overwritten by merge:

    这种情况下,如何保留本地的修改同时又把远程的合并过来呢? 首先取决于你是否想要保存本地修改.(是 /否) 是 git stash git pull origin master git stash po ...

  5. java001-泛型

    泛型出现的意义: 为编码阶段的不确定性和转化做视觉设计 将运行期遇到的问题转移到编译期,省去了强转的麻烦 package com.xiaolin.basic; /** * 泛型:将运行期遇到的问题转移 ...

  6. Spring Boot(二):Spring Boot中的配置参数

    Spring Boot 配置参数 Spring Boot 帮助我们完成了许许多多的自动化配置 如果我们需要根据自己的需求修改配置 也是可以的 可以使用.properties 和 .yml 格式配置 这 ...

  7. Java基础00-基础知识练习12

    1. 减肥计划 1.1 if语句实现 import java.util.Scanner; public class Demo01 { public static void main(String[] ...

  8. Function.identity()

    Java 8允许在接口中加入具体方法.接口中的具体方法有两种,default方法和static方法,identity()就是Function接口的一个静态方法.Function.identity()返 ...

  9. 全面了解Nginx到底能做什么

    最近做项目需要动静分离,便用nginx的反向代理来实现.后来看到一篇好文,记录下. 来自https://www.jianshu.com/p/8bf73d1a758c 前言 本文只针对Nginx在不加载 ...

  10. Java电话薄项目(Java基础入门)

    面向对象程序设计(Java基础) 1.项目介绍: 该项目能够实现对电话薄的添加,查找,修改,删除,排序等基本操作. 用户进入系统中首先进入主菜单中,在主菜单中可以选择相应的操作,用户可以选择每项操作前 ...