当前位置: 首页 > news >正文

[蓝桥杯 2022 国 B] 卡牌(贪心/二分)

题目传送门 

该题第一思路是想去模拟题目中所描述的过程

这里我选择从大到小遍历可能凑出的牌套数,计算凑出它需要补的牌数以及判断是否会超出能补的牌数

#include<iostream>
#include<climits>
#include<vector>
#include<algorithm>
#define int long long using namespace std;const int MAX=2e5+10;int a[MAX];
int b[MAX];
int n,m,ans=0,num=0;
vector<int>v;signed main(){cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];v.push_back(a[i]);}for(int i=1;i<=n;i++){cin>>b[i];}sort(v.begin(),v.end());//排序for(int i=n-1;i>=0;i--){//尝试将每一种卡牌都变成v[i]张 int ele=v[i];int sign=0;int sum=0; for(int j=1;j<=n;j++){int need=v[i]-a[j];//需要补上 if(need>0)sum+=need;if(b[j]-need<0){sign=1; break;//不能补 } }if(sum>m||sign){continue;}else{cout<<v[i]<<endl;break;}} return 0;
}

由于该算法效率低下并不能通过所有样例

但是仔细理解题意,我们可以发现该方法可以使用二分进行优化

#include<iostream>
#include<algorithm>
#define int long long
using namespace std;const int MAX=2e5+10;int n,m,l,r;
int a[MAX];
int b[MAX];bool check(int x){int s = 0;for (int i = 0; i < n; i++) {if (x - a[i] <= b[i]) {s += max(x - a[i], 0ll);//统计组成x套牌需要补s张牌}else return false;//超出了b[i]}if (s <= m) return true;//没有越界return false;
}signed main(){cin>>n>>m;for(int i=0;i<n;i++){cin>>a[i];l = min(l, a[i]);}for(int i=0;i<n;i++){cin>>b[i];r=max(r,a[i]+b[i]);}	int ans;while(l<=r){int mid=(l+r)/2;//二分组成的牌套数if(check(mid)){ans=mid;l=mid+1;}else{r=mid-1;}}cout<<ans<<endl;return 0;
}

 

第二思路是使用“贪心”的思想进行解答

首先要理解一个东西,卡牌套数等于最少的卡牌牌数。因为一套卡牌需要所有卡牌各一张,所以对于最少的卡牌,它如果只有 x 张,则只能有 x 套卡牌含有最少的卡牌。再多的其他卡牌就没用了,所以卡牌套数等于最少的卡牌牌数。

那具体怎么贪心呢?使卡牌套数最多。由于卡牌套数等于最少的卡牌牌数,只需要尽量让最终各种卡牌数量接近即可。那就优先画数量少的卡牌,直到空卡牌用完。

每次 O(n) 选择最小的卡牌,复杂度会很高。由于这个贪心策略是要连续选择最小的,所以可以通过排序来降低复杂度。

最后还有一个问题:可画的卡牌数有限制。还是根据卡牌套数等于最少的卡牌牌数,在空卡牌够用的情况下,最终的卡牌套数取决于初始卡牌数与可画卡牌数的和最少的卡牌。所以可以判断目前求得的卡牌数是否大于每张卡牌初始卡牌数与可画卡牌数的和的最小值来解决这个问题。若小于,继续贪心。若大于,则证明空卡牌够用,但受可画的卡牌数的限制,卡牌套数只能为每张卡牌初始卡牌数与可画卡牌数的和的最小值。(好吧这一段有点难理解,可以结合代码里的注释理解)

#include<iostream>
#include<algorithm> 
#include<climits>
#define int long longconst int MAX=2e6;using namespace std;int n,m;
int a[MAX];
int b;signed main(){int consume=0,minn=INT_MAX;cin>>n>>m;for(int i=0;i<n;i++){cin>>a[i];}for(int i=0;i<n;i++){cin>>b;if(a[i]+b<minn){minn=a[i]+b;//得到最大套牌数 } }sort(a,a+n);//其实无所谓对应下标 int ans=a[0];//初始值为最小牌数 for(int i=0;i<n;i++){if(i==n-1&&consume<m){ans+=(m-consume)/n;//剩余卡牌平均分 if(ans>minn)ans=minn;break; }if(a[i]<a[i+1]){//前面卡牌不够 //这里不能且无需去修改数组中的内容(会降低代码效率)consume+=(i+1)*(a[i+1]-a[i]);//消耗的卡牌ans+=(a[i+1]-a[i]); }if(consume>m)//不够牌补了{consume-=(i+1)*(a[i+1]-a[i]);ans-=(a[i+1]-a[i]);ans+=(m-consume)/(i+1);//平均分break; } if(ans>minn){ans=minn;break;}}cout<<ans<<endl;return 0;
}
http://www.lryc.cn/news/20355.html

相关文章:

  • 1301:大盗阿福
  • Netty——序列化的作用及自定义协议
  • 一起Talk Android吧(第五百零五回:如何调整组件在约束布局中的大小)
  • 【数据库】数据库的完整性
  • 基因净化车间装修设计方案SICOLAB
  • java 内部类的四种“写法”
  • 【python】main方法教程
  • 公司对不同职级能力抽象要求的具体化
  • Java之MinIO存储桶和对象API使用
  • 如何用java实现同时进行多个请求,可以将它们并行执行,从而减少总共的请求时间。
  • 高端装备的AC主轴头结构
  • 【Proteus仿真】【51单片机】粮仓温湿度控制系统设计
  • 【LINUX】环境变量以及main函数的参数
  • 使用Pyparsing为嵌入式开发定义自己的脚本语言
  • C win32基础学习(二)
  • 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?
  • 读书笔记//《数据分析之道》
  • 1个串口用1根线实现多机半双工通信+开机控制电路
  • KUKA机器人外部自动运行模式的相关信号配置
  • 【RabbitMQ笔记02】消息队列RabbitMQ七种模式之最简单的模式
  • Spring MVC 源码- RequestToViewNameTranslator 组件
  • Linux--TCP编程--0216 17
  • 关于设计模式的记录
  • Lambda-常见的函数式接口
  • P1196 [NOI2002] 银河英雄传说 带权并查集
  • 【项目实战】快来入门Groovy的基础语法吧
  • Mybatis中的动态SQL
  • VUE常用API
  • 25 openEuler管理网络-使用nmcli命令配置ip
  • 如何安装和使用A-ops工具?