问题:
分析:
我去年蓝桥杯做的题目,不知道做没做对,但是给的那个数据可以过,其他数据点就不知道了。
哈哈哈,当然我一开始也是猜测是不是二分,然后又想到二分要单调的,就用用二分找V,当时用的是整除的方法,也就是%,感觉也分的怪怪的。
今年我看了acwing的讲解,理解了一些东西。
1.二分的关键如何分这两部分
- 由数据太大,不能直接暴力求解,所以通过二分的方法来找。
- 这道题要做两次二分,分别去找最小数值,和最大数值。难点就在于求最大数值,如何来划分这个。因为Vmax对上去的B之后没有了,就到B-1了,所以要用下面这个点来分。即:search(A,B-1),而search(A,B-1)-1,再减去1是因为这个V是根据下一排来计算得到的,会比实际的V大,所以V要减去。
(图1来源于yxc讲解:AcWing 4956. 冶炼金属(春季每日一题2023) - AcWing)
2.多组数据如何统一取值:
结合数学知识来理解,求共同部分,用数轴来理解
根据图2求公共部分就可以知道,求V_min要取他们的最大值,求V_max要取他们的最小值
(图2)
3.一些细节问题
因为b-1的缘故,当b=1的时候,b-1=0,那么此时search(A,B-1),而且当A=1e9时,V=1e9只B只肯等于1,所以把V=1e9+1就可以了,(yxc是这么说的:此时不管A是多少,此时B都为1,我感觉这是一个近似),但没有+1也没关系,蓝桥的测试数据也能过。
代码:
代码也是学yxc的代码,他的代码写的好简洁明了!!
小菜菜我哭了。
//二分的条件是:1.数值单调 2。由两部分的条件不一样
//这道题对1到N的所有数据进行二分。
//二分的条件看这个图
//取max还是min根据集合(线段)来想
//求整,可以由不等式代替
#include<iostream>
//lanqiao3510 acwing 4956
#include<algorithm>
#include<cstring>
using namespace std;
int N;
int A,B,V_min,V_max;
int search(int a,int b)
{
//在l和r中寻找V,l是分母最小为1,考虑到B可能是1,所以要把V的范围稍稍整理大一点,不然容易出错
int l=1,r=1e9+1;
while(l<r)
{
int mid=l+(r-l) /2;
if(a/mid<=b) r=mid; //这里用等于,见这个图
else l=mid+1;
}
//找到了就返回,和上一个二分有点不一样
return r; //返回return r的原因还是看那个图
}
int main()
{
int V_min=1,V_max=1e9; //B在题目中有范围要大于或者等于1
scanf("%d",&N);
for(int i=0;i<=N;i++)
{
scanf("%d%d",&A,&B);
V_min=max(V_min,search(A,B));
V_max=min(V_max,search(A,B-1)-1); //下一段的开头,所以B-1,而且V也会减去1
}
printf("%d %d",V_min,V_max);
return 0;
}