题目描述
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O 恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。
现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。
输入 #1
3
75 3
53 2
59 2
输出 #1
20 25
【样例说明】
当 V=20 时,有:⌊75/20⌋=3,⌊53/20⌋=2,⌊59/20⌋=2⌊20/75⌋=3,⌊20/53⌋=2,⌊20/59⌋=2,可以看到符合所有冶炼记录。
当 V=25 时,有:⌊75/25⌋
=3,⌊53/25⌋=2,⌊59/25⌋=2⌊25/75⌋=3,⌊25/53⌋=2,⌊25/59⌋=2,可以看到符合所有冶炼记录。
且再也找不到比 2020 更小或者比 2525 更大的符合条件的 V 值了。
对于 100%100% 的评测用例,1<=N<=1e4;1<=A,B<=1e9;
这道题主要考察二分答案,关于二分的一些知识可以参考这类文章。
对于75 3这个数据,就是求75除于一个什么数可以等于3,可知这个答案属于一个区间,所以直接按照二分答案模板套用,找75除以一个什么数可以等于3的左右边界,最后再给这三个数据取一个并集就可以的得到答案。但这道题并不是让求集合,所以我们只需要求这个集合的最大最小值就可以了。
附上我的代码
#include <bits/stdc++.h> #define int long long//这里直接开long long using namespace std; int x,y; int check1(int q)//找右边界 { if (x/q>=y) //这里的条件需要注意一下,两个check函数条件不一样 return 1; return 0; } int check2(int q)//找左边界 { if (x/q>y)//注意一下条件 return 0; return 1; } signed main () { int n;cin>>n;int ans2=INT_MAX,ans1=INT_MIN;//这里直接用limits.h的函数方便比较,但是我们写了万能头文件,所以不用写头文件了 for (int i=1;i<=n;i++) { cin>>x>>y; int l=1,r=1000000001; while (l<r) { int mid=(l+r+1)>>1; if (check1(mid))l=mid; else r=mid-1; }//二分答案模板找右边界,边界是l; ans2=min(l,ans2);//在循环里面比较,最后得出来的值就是我们要的集合区间最大值 int l1=1,r1=1000000001; while (l1<r1) { int mid1=(l1+r1)>>1; if (check2(mid1))r1=mid1; else l1=mid1+1; }//二分答案模板找左边界,边界是r; ans1=max(r1,ans1);//在循环里面比较,最后得出来的值就是我们要的集合区间最小值 } cout<<ans1<<' '<<ans2;//最后输出,完美撒花 }