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

P13013 GESP5级202506 编程T1--奖品兑换

P13013 [GESP202506 五级] 奖品兑换

题目背景

为了保证只有时间复杂度正确的代码能够通过本题,时限下降为 400 毫秒。

题目描述

班主任给上课专心听讲、认真完成作业的同学们分别发放了若干张课堂优秀券和作业优秀券。同学们可以使用这两种券找班主任兑换奖品。具体来说,可以使用 aaa 张课堂优秀券和 bbb 张作业优秀券兑换一份奖品,或者使用 bbb 张课堂优秀券和 aaa 张作业优秀券兑换一份奖品。

现在小 A 有 nnn 张课堂优秀券和 mmm 张作业优秀券,他最多能兑换多少份奖品呢?

输入格式

第一行,两个正整数 n,mn,mn,m,分别表示小 A 持有的课堂优秀券和作业优秀券的数量。

第二行,两个正整数 a,ba,ba,b,表示兑换一份奖品所需的两种券的数量。

输出格式

输出共一行,一个整数,表示最多能兑换的奖品份数。

输入输出样例 #1

输入 #1

8 8
2 1

输出 #1

5

输入输出样例 #2

输入 #2

314159 2653589
27 1828

输出 #2

1599

说明/提示

对于 60%60\%60% 的测试点,保证 1≤a,b≤1001 \le a,b \le 1001a,b1001≤n,m≤5001 \le n,m \le 5001n,m500

对于所有测试点,保证 1≤a,b≤1041 \le a,b \le 10^41a,b1041≤n,m≤1091 \le n,m \le 10^91n,m109

Bilibili视频

先康康我的bilibili视频

(进度条不对劲)家人们出事啦!我用O(2^n)的递归方式,居然AC了n在10000以内的题目!


10分钟,很长的。
这个视频针对这道题给出了三种解法:递归、贪心、二分。
如果考试问你学到什么道理,直接抄上!
在这里插入图片描述

题目大意

给定四个正整数nnn,mmm,aaa,bbb,分别表示手里的课堂优秀券、手里的作业优秀券、一个奖品需要的课堂优秀券、一个奖品同时需要的作业优秀券(aaa,bbb可以随时交换,视频忘说了)

递归解法

假设递归函数为dfs,那么应该传入这些参数:i j cnt,表示剩余课堂优秀券、剩余作业优秀券、已获得奖品数量。
对于dfs(i,j,cnt)可以推出dfs(i-a,j-b,cnt+1)dfs(i-b,j-a,cnt+1),前提是够换奖品。
先别管超时,我们先写代码。

#include<bits/stdc++.h>
using namespace std;
int a,b,mx;
void dfs(int i,int j,int cnt)
{mx=max(mx,cnt);if(i>=a&&j>=b)dfs(i-a,j-b,cnt+1);if(i>=b&&j>=a)dfs(i-b,j-a,cnt+1);
}
int main()
{int n,m;cin>>n>>m>>a>>b;dfs(n,m,0);cout<<mx;return 0;
}

一号样例过
在这里插入图片描述
遇到二号就噶了
在这里插入图片描述
提交逝世
在这里插入图片描述
我怎么感觉二号样例有助于我们背圆周率呢
这里有12个AC,4个TLE,4个MLE,其中tle是超时,mle是超内存(超递归栈)

递归复杂度

每个递归函数引导两个子函数,差不多O(2n)O(2^n)O(2n)吧?
空间应该就是O(n)O(n)O(n)了,细致的说,O(na+mb)O(\frac{n}{a}+\frac{m}{b})O(an+bm)(并不准)

贪心

我们尽可能地让n,mn,mn,m中的较大者去减a,ba,ba,b中的较大者,较小者同理,这样分配对n,mn,mn,m公平,可以多分点。
于是代码就"bang"出来了

#include<bits/stdc++.h>
using namespace std;
int main()
{int n,m,a,b,cnt=0;cin>>n>>m>>a>>b;while(n>=a&&m>=b||n>=b&&m>=a) //c++中,先算&&,再算||{if(n>=m) //n大,优先选n-max a,b{n-=max(a,b);m-=min(a,b);}else //m大,优先选m-max a,b{n-=min(a,b);m-=max(a,b);}cnt++;}cout<<cnt;return 0;
}

样例1、2全都能通过
在这里插入图片描述
然而提交时的你又双叒叕(you4 shuang1 ruo4 zhuo2)傻眼了
在这里插入图片描述
哇!第17个点正好超时1ms
就在你想放弃时,突然点到了展开算法标签。
在这里插入图片描述
二分!?我想试试。
有谁注意到了
在这里插入图片描述

二分AC版

我们假设最多兑换的奖品份数为xxx,思考🤔如何判断xxx是不是合法的奖品份数(小于等于标准答案)。
首先调整a<ba<ba<b以便后期操作。
n≥axn\ge axnax并且m≥axm\ge axmax时,必然兑换够用!其中第二种利用aaabbb小,尽量让后面的剩余资源空间大。
那么如果是两种方案混合来呢?
我们来看一句话:
“今有鸡兔同笼,上有三十四头,下有九十四足,问鸡兔各几何?”
我们一般用假设法来解决鸡兔同笼问题,设全都是什么,然后把一部分变成另一种,最后求出数量。
那么这道题也可以用假设法。
现在假设全都是a,ba,ba,b类(aaa课堂bbb作业),要想改成b,ab,ab,a类,就要多搞来b−ab-aba个课堂优秀券。而n−axn-axnax是剩下的课堂优秀券,因此⌊n−axb−a⌋\lfloor\frac{n-ax}{b-a}\rfloorbanax就是b,ab,ab,a类的数量,同理。
假设全都是b,ab,ab,a类,要想改成a,ba,ba,b类,就要多搞来b−ab-aba个作业优秀券。而m−axm-axmax是剩下的作业优秀券(因为a,ba,ba,b可以互换,aaa更小剩余的更大),因此⌊m−axb−a⌋\lfloor\frac{m-ax}{b-a}\rfloorbamax就是a,ba,ba,b类的数量。
如果他们加起来小于xxx,就说明xxx太大了,因此可以把他们存进check函数,对于后面的二分答案有帮助。

bool check(int num)
{if(n<a*num || m<a*num)return false;int ab=(m-a*num)/(b-a),ba=(n-a*num)/(b-a);return ab+ba>=num;
}

因为二分经常写错,所以提一点
1 当check(mid)返回truel=mid,因为合法, l不能加111
2 当check(mid)返回falser=mid-1,因为不合法,r必须减111
3 mid=(l+r+1)/2,因为l=3 r=4时,(l+r)/2check(3)=true时,mid会一直等于333l永远不变,也就超时了,(l+r+1)/2可以避免。
4 l<r是循环进入条件,如果有等于那么lr会永久重合,TLE了。
知道这一点,没问题了,开始写Code吧!

AC Code

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b;
bool check(int num)
{if(n<a*num || m<a*num)return false; //基础资源分配int ab=(m-a*num)/(b-a),ba=(n-a*num)/(b-a); //a,b类b,a类转换return ab+ba>=num;
}
int main()
{cin>>n>>m>>a>>b;if(a>b)swap(a,b); //调整a和b大小if(a==b){cout<<min(n,m)/a;return 0;} //直接计算long long l=0,r=2e9;while(l<r){int mid=(l+r+1)/2;if(check(mid))l=mid; //合法else r=mid-1; //不合法}cout<<l;return 0;
}

目前这个代码是能通过样例的,l r必须开long longmid可以不用。
在这里插入图片描述

在这里插入图片描述
孩子们!mid要开long long,想起那个WA时钢管掉落的声音了吗!
因为check里面对mid和其他变量进行了乘法,必须开long long!!!

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b;
bool check(int num)
{if(n<a*num || m<a*num)return false; //基础资源分配int ab=(m-a*num)/(b-a),ba=(n-a*num)/(b-a); //a,b类b,a类转换return ab+ba>=num;
}
int main()
{cin>>n>>m>>a>>b;if(a>b)swap(a,b); //调整a和b大小if(a==b){cout<<min(n,m)/a;return 0;} //直接计算long long l=0,r=2e9;while(l<r){long long mid=(l+r+1)/2;if(check(mid))l=mid; //合法else r=mid-1; //不合法}cout<<l;return 0;
}

样例不用说了肯定对了
(一种植物)
在这里插入图片描述
孩子们!check里面的num也要开long long!!!
(一个二分代码改了三次)

#include<bits/stdc++.h>
using namespace std;
int n,m,a,b;
bool check(long long num)
{if(n<a*num || m<a*num)return false; //基础资源分配int ab=(m-a*num)/(b-a),ba=(n-a*num)/(b-a); //a,b类b,a类转换return ab+ba>=num;
}
int main()
{cin>>n>>m>>a>>b;if(a>b)swap(a,b); //调整a和b大小if(a==b){cout<<min(n,m)/a;return 0;} //直接计算long long l=0,r=2e9;while(l<r){long long mid=(l+r+1)/2;if(check(mid))l=mid; //合法else r=mid-1; //不合法}cout<<l;return 0;
}

啊!终于AC了
在这里插入图片描述

总结

这道题其实难在二分公式的数学推导,其他没啥大问题,注意long long就行。
GodBye

http://www.dtcms.com/a/404113.html

相关文章:

  • 微信推广网站怎么做asp网站域名授权
  • 建设网站的新闻湘潭做网站 m磐石网络
  • 健身房管理系统的设计与实现
  • seo站外推广有哪些工商网站注册公司
  • 为什么网站上传都上传不成功网站做付费推广都需要问什么
  • 滨州做企业网站云南有哪些城市
  • Visual Studio C/C++函数/方法使用Doxygen格式注释
  • 河北自助建站系统平台帝国cms源码
  • 信誉好的顺德网站建设团购网站案例
  • Coach系统精读分析:基于时序模式的云平台全资源超售【无标题】
  • 陕煤化建设集团网站矿建二公司奉化网站关键词优化费用
  • 产品网站开发服务阿里指数查询入口
  • 网站建设流程及相应技术网页升级访问中新每天正常更新中
  • 下沙做网站的网页设计模板html代码班级主题
  • 网站添加flv视频代码创意工作室网站
  • MySQL-事务基础
  • 学习游戏制作记录(史莱姆敌人的制作)
  • 创建一个网站一般步骤有哪些网站开发python
  • 江苏省建设厅官网网站首页网站建设二次开发怎么样
  • 安徽网站建设公司哪家好上海域名icp海网站建设
  • 北京住房城乡建设部网站首页搭建论坛需要多少钱
  • 养老网站建设方案咨询类网站建设方案书
  • Java算法起航:数据结构与复杂度入门
  • 市北区开发建设局 网站老客户网站建设
  • 足球直播网站开发定制检察院网站建设
  • dw软件网站建设教程视频云阳网站建设公司
  • Ubuntu 20.04上安装Miniconda3(一)
  • 免费网站模板素材一般淘宝网站做几个月赚钱
  • 可以做设计兼职的网站有哪些工作狮城app更多网站
  • 区域提议(Region Proposal)