P9240 [蓝桥杯 2023 省 B] 冶炼金属 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
===============================================================
参考题解:
#C++3150——蓝桥杯2023年第十四届省赛真题-冶炼金属(分块)-Dotcpp编程社区
================================================================
对第一种解法做一个备忘的笔记(二分的部分放在评论区):
关于一个记录的最大v和最小v,即
int max=a/b,min=a/(b+1);
//对于max这个式子,求出的max肯定是合法的,max如果再大1,a不变(普通金属总量不变)那么b肯定变小,就不能冶炼出那么多金属,就不合法了;而min是除以原有冶炼数量+1,得到一个数,这个数肯定是不合法的,但是可以看成是这个冶炼数量(原有冶炼数量+1)的最大v,所以再加上1就是原有冶炼数量的最小值 。
#include<bits/stdc++.h>
#define int long long
using namespace std;
signed main(){
int n;
cin>>n;
int a,b;
cin>>a>>b;
int max=a/b,min=a/(b+1);
//max如果再大,a不变那么b肯定变小,就不能冶炼出那么多金属,就不合法了;而min是除以原有冶炼数量+1,得到一个数,
//这个数肯定是不合法的,但是是这个冶炼数量的最大v,所以再加上1就是原有冶炼数量的最小值
n--;
while(n--){
cin>>a>>b;
if(max>a/b) max=a/b;
if(min<a/(b+1)) min=a/(b+1);
}
cout<<min+1<<" "<<max;
return 0;
}
想到二分主要是首先想到枚举v。最小的v是从1枚举到一个较大的数,然后用这个数去一一地检测是否满足每一条记录,但是这样运行时间过长。所以要考虑二分,因为v的序列是一个递增的序列,满足二分的条件,而合法的v区间满足对b[i]==a[i]/v。条件的判断也满足着线性的大小关系。比如v大到超出合法区间,总有一条记录是b[i]>a[i]/v,且v继续增大也满足这个关系。
这里要注意的是,不合法的时候是至少有一条记录不满足,而不是全部记录不满足。