目录
一.题目
二.二分
网上这种教程已经有很多了,个人选择一个我比较喜欢的讲解吧~
【二分查找】详细图解_二分查找法流程图-优快云博客https://blog.youkuaiyun.com/qq_45978890/article/details/116094046
三.思路整理
首先分析什么样的V是满足题目中所设条件的,假设第i组的数据为A[i],B[i],那么V肯定满足:
对于任意一个i<=N,始终满足B[i]=A[i]/V
那么对于暴力做法,就是枚举每一个V,看是否满足这个条件,但是这样的时间复杂度是否太大了。所以说我们的追求不止于此
根据题目中需要我们做出来的结果,我们分析一下这个V的范围的边界:
对于Vmin:
当V<Vmin的时候,我们只要检测出存在一个i,使得B[i]>A[i]/V,就说明这个V不存在在这个区间中,那我们将这个V替换成mid=(left+right)/2,那么此时我们的左指针left=mid;
同理,当V>Vmin的时候,任意一个i,都满足B[i]<A[i]/V。其实这两个互为否命题,那什么最简单最容易检测的呢?当然是前者啦,我们遍历整个数据,只要找到一组数据不满足这个条件,我们就break循环,而第二个由于是否命题,直接用else 即可
对于Vmax:
同理,这里留着给大家自己思考~
四.二分使用方法总结
发现没有,我们这里是直接把结果假设框定了一个范围,然后用左右指针去二分这个区间的左右端点。那这道题我们可以总结一下步骤:
- 首先分析了单个V应该满足什么样的条件
- 首先由结果进行分析,由题目的问法求Vmin和Vmax我们可以确定所得到的V是个范围,有多个V满足这些条件
- 对于V的取值可以排列成一个递增的数组,满足二分的条件。那么就可以使用二分对于左右指针进行值查找
五.代码
//冶炼金属:二分
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e4 + 10;
int a[N], b[N];
int n;
bool check_min(int mid)
{
for(int i = 0; i < n; i ++)
{
if(b[i] < a[i] / mid)
return false;
}
return true;
}
bool check_max(int mid)
{
for(int i = 0; i < n; i ++)
if(b[i] > a[i] / mid)
return false;
return true;
}
void solve()
{
cin >> n;
for(int i = 0; i < n; i ++)
cin >> a[i] >> b[i];
//求最小值。
int lmin = 1, rmin = 1e9;
while(lmin < rmin)
{
int mid = lmin + rmin >> 1;
if(check_min(mid))
rmin = mid;
else
lmin = mid + 1;
}
//求最大值。
int lmax = 1, rmax = 1e9;
while(lmax < rmax)
{
int mid = lmax + rmax + 1 >> 1;
if(check_max(mid))
lmax = mid;
else
rmax = mid - 1;
}
cout << lmin << " " << lmax << endl;
}
signed main()
{
ios::sync_with_stdio(0);
int t = 1;
// cin >> t;
while(t--)
solve();
}