冶炼金属
注意以下这种写法是错误的 二分板子只能在一个题中出现一次
这题与789数的范围那题不一样的一点是数的范围是 一个>=时动r 另一个板子是>r时动r
而这题只是判断mid这个值是否满足条件 因此只能用二分板子中的一个 而不能两个都用去判断一个左边界一个右边界
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int a[N],b[N];
int n;
bool check(int mid)
{
for(int i=0;i<n;i++)
{
if(a[i]/mid<b[i]) return false;
}
return true;
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
scanf("%d%d",&a[i],&b[i]);
}
int l=0,r=1e9+10;
while(l<r)
{
int mid=l+r>>1;
if(!check(mid)) r=mid;
else l=mid+1;
}
cout<<r<<' ';
l=0,r=1e9+10;
while(l<r)
{
int mid=(l+r+1)>>1;
if(check(mid)) l=mid;
else r=mid-1;
}
cout<<r;
return 0;
}
正确的做法:
vmin:A/V=b:最小的v
vmax:A/V=b-1: 最小的v-1
#include<bits/stdc++.h>
using namespace std;
int get(int a,int b)
{
int l=1,r=1e9+1;//因为转化率又可能为0 当l=1e9时不会出现0 因此r要+1
while(l<r)
{
int mid=l+r>>1;
if(a/mid<=b) r=mid;
else l=mid+1;
}
return r;
}
int main()
{
int n;
cin>>n;
int v_min=1,v_max=1e9;
while(n--)
{
int a,b;
cin>>a>>b;
v_min=max(v_min,get(a,b));
v_max=min(v_max,get(a,b-1)-1);//由于v只能取整数 因此要-1
}
printf("%d %d",v_min,v_max);
return 0;
}
或者:
[A/V]=B;
B<=A/V<=B+1
1/(B)>=V/A>=1/(B+1)
A/(B+1)<=V<=A/B
[A/(B+1)]+1<=V<=[A/B]
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
//初始化转化率的最小值v_min和最大值v_max,v_min起始为1(至少需要1个普通金属O来转换特殊金属X),v_max起始设置为一
//个较大的数
int v_min=1,v_max=1e9;
while(n--)
{
int a,b;
scanf("%d%d",&a,&b);
//更新转换率v_min:由于每次冶炼必须是整数个普通金属O,所以实际转换率至少应该是a/(b+1)向上取整的结果
//即加上1 这里用max函数保证每次更新后v_min变得更大
v_min=max(v_min,(a+b)/(b+1));
//等价于a/(b+1)+1
//更新转换率 v_max:为了使得冶炼记录成立,转换率V应该不大于a/b的结果向下取整 这里用min函数保证变得更小
v_max=min(v_max,a/b);
}
cout<<v_min<<' '<<v_max<<endl;
return 0;
}