> 文章列表 > 蓝桥杯B组C题冶炼金属(二分查找)

蓝桥杯B组C题冶炼金属(二分查找)

蓝桥杯B组C题冶炼金属(二分查找)

        

C: 冶炼金属(10分)
问题描述
小蓝有一个神奇的炉子用于将普通金属O OO 冶炼成为一种特殊金属X XX。这个炉子有一个称作转换率的属性V VV,V VV 是一个正整数,这意味着消耗V VV 个普通金属O OO 恰好可以冶炼出一个特殊金属X XX,当普通金属O OO 的数目不足V VV 时,无法继续冶炼。

现在给出了N NN 条冶炼记录,每条记录中包含两个整数A AA 和B BB,这表示本次投入了A AA 个普通金属O OO,最终冶炼出了B BB 个特殊金属X XX。每条记录都是独立的,这意味着上一次没消耗完的普通金属O OO 不会累加到下一次的冶炼当中。

根据这N NN 条冶炼记录,请你推测出转换率V VV 的最小值和最大值分别可能是多少,题目保证评测数据不存在无解的情况。

输入格式
第一行一个整数N NN,表示冶炼记录的数目。
接下来输入N NN 行,每行两个整数A AA、B BB,含义如题目所述。

输出格式
输出两个整数,分别表示V VV 可能的最小值和最大值,中间用空格分开。

样例输入
3
75 3
53 2
59 2

样例输出
20 25

样例说明
当V = 20 V = 20V=20 时,有:⌊ 75 20 = 3 ⌋ \\lfloor \\frac{75}{20}=3 \\rfloor⌊ 
20
75
​    
 =3⌋,⌊ 53 20 = 2 ⌋ \\lfloor \\frac{53}{20}=2 \\rfloor⌊ 
20
53
​    
 =2⌋,⌊ 59 20 = 2 ⌋ \\lfloor \\frac{59}{20}=2 \\rfloor⌊ 
20
59
​    
 =2⌋可以看到符合所有冶炼记录。
当V = 25 V = 25V=25 时,有:⌊ 75 25 = 3 ⌋ \\lfloor \\frac{75}{25}=3 \\rfloor⌊ 
25
75
​    
 =3⌋,⌊ 53 25 = 2 ⌋ \\lfloor \\frac{53}{25}=2 \\rfloor⌊ 
25
53
​    
 =2⌋,⌊ 59 25 = 2 ⌋ \\lfloor \\frac{59}{25}=2 \\rfloor⌊ 
25
59
​    
 =2⌋可以看到符合所有冶炼记录。
且再也找不到比20 2020 更小或者比25 2525 更大的符合条件的V VV 值了。

评测用例规模与约定
对于30 % 30\\%30% 的评测用例,1 ≤ N ≤ 1 0 2 1 ≤ N ≤ 10^21≤N≤10 
2
 。
对于60 % 60\\%60% 的评测用例,1 ≤ N ≤ 1 0 3 1 ≤ N ≤ 10^31≤N≤10 
3
 。
对于100 % 100\\%100% 的评测用例,1 ≤ N ≤ 1 0 4 1 ≤ N ≤ 10^41≤N≤10 
4
 ,1 ≤ B ≤ A ≤ 1 0 9 1 ≤ B ≤ A ≤ 10^91≤B≤A≤10 
9
 。

#include <iostream>
#include<vector>
using namespace std;

typedef long long LL;
typedef pair<LL, LL >PII;

const int N = 10010;
PII arr[N];
int n = 0;

int check(LL mid)
{
    for (int i = 0; i < n; i++)
    {
        if (arr[i].second * mid > arr[i].first && arr[i].first / mid != arr[i].second)return 1; //过大了
        else if (arr[i].second * mid < arr[i].first && arr[i].first / mid != arr[i].second)return 2;//过小了
    }
    return 0;
}

//check里要注意一个点,first/mid>second 与 sceond*mid<first 是不一样的
//假设arr[i]为  75 与 3,然后就可以分为三个区间,a:0--19,b:20--25,c:25--1e9
//75/a一定大于3  75/b一定为3   75/c一定小于3
//判断时,要判断mid属于某个区间且不属于另外两个区间
//前者完美解决此问题,后者就要加上别的判断语句

int main()
{
    cin >> n;
    for (int i = 0; i < n; i++)
    {
        cin >> arr[i].first >> arr[i].second;
    }
    LL l = 0;
    LL r = 1e9;
    while (l < r)//求最小值
    {
        LL mid = (l + r) / 2;
        if (check(mid) == 1)r = mid - 1;      //过大的时候
        else if (check(mid) == 2)l = mid + 1; //过小的时候
        else if (check(mid) == 0)r = mid;     //处于答案的区域
    }
    cout << l << endl;
    l = 0;
    r = 1e9;
    while (l < r)//求最大值
    {
        LL mid = (l + r) / 2;
        if (check(mid) == 1)r = mid - 1;      //过大的时候
        else if (check(mid) == 2)l = mid + 1; //过小的时候
        else if (check(mid) == 0)l = mid;     //处于答案的区域
    }
    cout << l << endl;
}