P9240 [蓝桥杯 2023 省 B] 冶炼金属【一图胜千言】

😊😊 😊😊
不求点赞,只求耐心看完,指出您的疑惑和写的不好的地方,谢谢您。本人会及时更正感谢。希望看完后能帮助您理解算法的本质
😊😊 😊😊

[蓝桥杯 2023 省 B] 冶炼金属

题目描述

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

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

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

输入格式

第一行一个整数 N N N,表示冶炼记录的数目。

接下来输入 N N N 行,每行两个整数 A , B A,B A,B,含义如题目所述。

输出格式

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

样例 #1

样例输入 #1

3
75 3
53 2
59 2

样例输出 #1

20 25

提示

【样例说明】

V = 20 V=20 V=20 时,有: ⌊ 75 20 ⌋ = 3 , ⌊ 53 20 ⌋ = 2 , ⌊ 59 20 ⌋ = 2 \left\lfloor\frac{75}{20}\right\rfloor=3,\left\lfloor\frac{53}{20}\right\rfloor=2,\left\lfloor\frac{59}{20}\right\rfloor=2 2075=3,2053=2,2059=2,可以看到符合所有冶炼记录。

V = 25 V=25 V=25 时,有: ⌊ 75 25 ⌋ = 3 , ⌊ 53 25 ⌋ = 2 , ⌊ 59 25 ⌋ = 2 \left\lfloor\frac{75}{25}\right\rfloor=3,\left\lfloor\frac{53}{25}\right\rfloor=2,\left\lfloor\frac{59}{25}\right\rfloor=2 2575=3,2553=2,2559=2,可以看到符合所有冶炼记录。

且再也找不到比 20 20 20 更小或者比 25 25 25 更大的符合条件的 V V V 值了。

【评测用例规模与约定】

对于 30 % 30 \% 30% 的评测用例, 1 ≤ N ≤ 1 0 2 1 \leq N \leq 10^{2} 1N102

对于 60 % 60 \% 60% 的评测用例, 1 ≤ N ≤ 1 0 3 1 \leq N \leq 10^{3} 1N103

对于 100 % 100 \% 100% 的评测用例, 1 ≤ N ≤ 1 0 4 1 \leq N \leq 10^{4} 1N104 1 ≤ B ≤ A ≤ 1 0 9 1 \leq B \leq A \leq 10^{9} 1BA109

蓝桥杯 2023 省赛 B 组 C 题。

小白到进阶各种解法:

一、暴力枚举:😊

思路:

简化问题 :不要一上来就分析多条记录,而是分析一条记录,找出问题的本质;

分析题目性质:

1、A个O生成B个X,我们要求A个O恰好生成B个X的转化率,转化率分为最大转化个数 m a x V max_V maxV 和 最小转化个数 m i n V min_V minV

m i n V min_V minV:表示 A 个 O A个O AO 恰好生成 B 个 X B个X BX 的所需的最小消耗值;
m a x V max_V maxV:表示 A 个 O A个O AO 恰好生成 B 个 X B个X BX 的所需的最大消耗值;

2、所求转化率必须是能够使 A个O恰好能生成B个X;不能多一个X也不能少一个X;也就是说:max_V 和 min_V都要能使得A个O恰好生成B个X。

3、 A / V = = B A/V == B A/V==B 该公式随着 V V V 的增大而减少!可看作是单调递减的!
在这里插入图片描述

问题:

1、如何求:A个O恰好能生成B个X所需要的最大转化个数 max_V 和 最小转化个数 min_V 呢?

答: 可以直接循环暴力枚举V,从 V = 1 V=1 V=1 开始,但是有同学会问:那么循环到什么时候结束呢?首先 V V V 是将 A 个 O A个O AO 转化为 B 个 X B个X BX,假如 V > A V > A V>A,那还能转化吗?很明显是不能了,所以 V V V 的最大枚举到 A A A 即可!

循环体内部:判断 A / V = B A / V = B A/V=B 如果等于的话,则分别与 m a x V max_V maxV m i n V min_V minV 取最值。若不等于的话,则枚举下一个 V V V ;当

加个优化: i f ( A / V < B ) if (A/V < B) if(A/V<B) 则由于随着 V V V 的增大, A / V A/V A/V的值单调递减,所以若往后继续枚举的话, A / V A/V A/V 的值将永远不会再大于 B B B了! 而 V V V 从1开始枚举的时候,是最大的, A / 1 , A / 2 , A / 3 , , , A/1,A/2,A/3,,, A/1A/2A/3,,, 所以这时候可以直接 b r e a k break break
在这里插入图片描述
时间复杂度:由于 需要循环枚举的是 V V V V V V 的枚举范围取决于 A A A,而 A A A 的最大值是: 1 e 9 1e9 1e9,所以很容易超时,故该算法超时!

部分代码:针对一条记录而言:

int a, b;
	cin >> a >> b;
	int min_v = inf;
	int max_v = 0;
	for (int v=1; v <= a; v ++)
	{
		if (a/v == b) {
			min_v = min(min_v, v);
			max_v = max(max_v, v);
		}
		
		if (a/v < b) {
			break;
		}
	}

针对多条记录:
而本题要求的是:多条记录,即你的两个 V V V 求出来要满足每条记录的 A 个 O A个O AO 恰好生成 B 个 X B个X BX
直接一图胜千言吧:批注:该图在下文二分里面也会用到:
在这里插入图片描述

假设当前是三条记录的话:那么我们要找的是一个公共的 V V V 值,能同时满足三条记录的最小转化值和最大转化值!!!!

而公共最小值的话:就是从最小值集合里面: [ m i n V 1 , m i n V 2 , m i n V 3 ] [min_V1,min_V2,min_V3] [minV1minV2minV3] 中挑选出最大的那个,对于 m a x V max_V maxV 也是同理!

这也是本题所求解的核心,就是叫你去求解这个!!!!!
结论:最小值里选取最大值,最大值里面选取最小值!

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
int n;
const int inf = 0x3f3f3f3f;
int Min_V=0, Max_V=inf;

int main()
{
	cin >> n;
	
	while (n --)
	{
		int a, b;
		cin >> a >> b;
		int min_v = inf;
		int max_v = 0;
		for (int v=1; v <= a; v ++)
		{
			if (a/v == b) {
				min_v = min(min_v, v);
				max_v = max(max_v, v);
			}
			
			if (a/v < b) {
				break;
			}
		}
		//该条记录的最小转化值和最大转化值取完了以后再与公共的最大转化值和最小转化值进行取最值!
		Min_V = max(Min_V, min_v);
		Max_V = min(Max_V, max_v);
	}
	
	cout << Min_V << " " << Max_V << endl;
	
	return 0;
} 

在这里插入图片描述

在这里插入图片描述

二、二分优化:😊

思路:结论:最小值里选取最大值,最大值里面选取最小值!

首先思考上面的代码里面超时的代码部分是在哪里?显然外层循环的 n n n 组数据是改变不了的,而内存里面的 f o r for for 循环将会超时,由于查找的 V V V 的范围过大而产生超时,所以说我们应该优化的是这里!而内层 f o r for for 循环所做的事情是:一个一个 V V V 地去枚举,由于枚举次数过多而超时!所以我们可以试着去减少枚举的次数!

注意上面暴力枚举思路里面的一句话,是使用二分的关键!
m i n V min_V minV:表示 A 个 O A个O AO 恰好生成 B 个 X B个X BX 的所需的最小消耗值;
m a x V max_V maxV:表示 A 个 O A个O AO 恰好生成 B 个 X B个X BX 的所需的最大消耗值;

从这句话里面我们可以看出有 m i n V min_V minV m a x V max_V maxV 之间必然也有一段 V V V 是能够使得 A 个 O A个O AO 恰好能生成 B 个 X B个X BX 的情况!

在这里插入图片描述

简化问题:依然是从一条记录开始分析。
这里再简化一下:因为我们是每消耗 V V V O O O 转化成一个 X X X V V V 的个数越少,消耗越少,越省钱,所以先求:要用 A 个 O A个O AO 恰好生产 B 个 X B个X BX的最小消耗的 V V V 的个数是多少?
如下图所示:
绿色部分表示: A / V > = B A/V >= B A/V>=B 的,合法但是不完全精确!
红色部分表示: A / V < B A/V < B A/V<B 的,表示完全不合法!
紫色部分表示: A / V = = B A/V == B A/V==B 的,是合法区域的值!
在这里插入图片描述
所以说最后要找的是:大绿色框框里面的部分:
在这里插入图片描述
开启上帝视角的话,找的应该是: V = = 5 V==5 V==5 这个值!即绿色和紫色的交界处:
在这里插入图片描述


那么对于数字 5 的查找就很 e a s y easy easy 了,直接将问题转化为找到第一个大于等于 5 的元素即可。
部分代码:即找到最小值!建议先不看这里

if (A/V <= B) R = mid;
else L = mid;

在这里插入图片描述

初始化: L = 0 , R = A + 1 , m i d = L + R > > 1 ; L = 0, R = A+1,mid = L+R >> 1; L=0R=A+1mid=L+R>>1;
如果 A / m i d < = B A/mid <= B A/mid<=B 则说明此时的 V V V 过大了,则移动右指针 R R R 使得 V V V值的范围变下,则下次再取 V V V 值的时候也必然变小,因为: L + R > > 1 = = m i d = = V L+R >> 1 ==mid ==V L+R>>1==mid==V R R R变小则 V V V 变小! L L L 变大,则 V V V也变大!

如果 A / m i d > B A/mid > B A/mid>B 则说明此时的 m i d 也就是 V mid也就是V mid也就是V V V V 偏小了但是合法,我们想看看当前这个 V V V 是否是恰好使得 A / m i d 恰好 = B A/mid 恰好= B A/mid恰好=B 的最小的 V V V,因为当前的 V V V 我们并不确定它是否是 恰好等于 的关系,所以说,我们还需要往右试探比当前这个 V V V 更大的 V V V 来看是否合法,如果比当前的 V V V 更小,并且 A / V > = B A/V >= B A/V>=B 则说明这个解更优!而如何枚举到比当前 V V V 更大的V呢?经过上段的分析可知:调整我们的 L L L 即可,使得它变大,所以此时应该执行的操作是: L = m i d L = mid L=mid


而接下来就是找 使得 A/mid == B 的最大V

建议先不看,自己推一遍,用:A=75 B=3 进行一遍模拟!
if (A/mid >= B) L = mid;		
else R = mid;	这种情况也就是:A/V >= B 的情况!!!!

此种情况下,二分的边界值为最大的 V V V ,能够使得 A 个 O A个O AO 恰好转化为 B 个 X B个X BX 的最大转化值 V = = 7 V == 7 V==7!即找到下图的紫色框框里最靠右边的值!
在这里插入图片描述

对于这两段代码的选取:
找大于等于某个数的最左边的一个值:
关键是 i f ( < = ) if(<=) if(<=) 里面的 <= 号!这样理解,如果你要找的是大于等于某个数最左边的值,那么就 <= 箭头朝左,加个等于号!

if (A/V <= B) R = mid;
else L = mid;

找大于等于某个数的最右边的一个值:
关键是 i f ( > = ) if(>=) if(>=) 里面的 >= 号!这样理解,如果你要找的是大于等于某个数最右边的值,那么就 >= 箭头朝右,加个等于号!

if (A/mid >= B) L = mid;		
else R = mid;	这种情况也就是:A/V >= B 的情况!!!!

如果是多条记录的话:
就是找最小值里面的最大值咯,比较每条记录的最小值,找最大的那个最小值 M i n V Min_V MinV,而该值一定能够满足每条记录都恰好转化出 B 个 X B个X BX

就是找最大值里面的最小值咯,比较每条记录的最大值,找最小的那个最大值 M a x V Max_V MaxV,而该值一定能够满足每条记录都恰好转化出 B 个 X B个X BX
一图胜千言!
在这里插入图片描述
结论:最小值里选取最大值,最大值里面选取最小值!

代码:

#include<iostream>
#include<cstring>
#include<algorithm>

using namespace std;
const int inf = 0x3f3f3f3f;
int n;		//n组数据! 
int Min_v=0, Max_v=inf;	//分别存储最小值集合里面最大的最小值,最大值集合里面的最小的最大值! 

int main()
{
	cin >> n;
	
	while (n --)
	{
		int a, b;
		cin >> a >> b;
		
		//找能够使得 A个O 恰好转化为 B个X的最小转化值! 
		int l=0, r=a+1;
		while (l + 1 != r)
		{
			int v = l + r >> 1;
			if (a/v <= b) r = v;		//找最小值的最大值,则是 <=,即找到合法区域里的左边界! 
			else l = v;
		}
		
		Min_v = max(Min_v, r);
		
		//找能够使得 A个O 恰好转化为 B个X的最大转化值! 
		l=0, r=a+1;
		while (l + 1 != r)
		{
			int v = l + r >> 1;
			if (a/v >= b) l = v;		//找最大值里的最小值,就是 >= 即找合法区域的右边界! 
			else r = v;
		}
		Max_v = min(Max_v, l);
	}
	
	cout << Min_v << " " << Max_v << endl;
	return 0;
}

在这里插入图片描述

在这里插入图片描述
每个人都有一个觉醒期,但觉醒期的早晚决定个人的命运。

三、二元不等式😊

代码:



在这里插入图片描述

每个人都有一个觉醒期,但觉醒期的早晚决定个人的命运。

  • 17
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
2023年华数杯中的B题是关于不透明制品的。不透明制品是指那些不透明或半透明的物品,例如陶瓷、金属、塑料等。这道题目可能涉及到不透明制品的性质、生产工艺、应用领域等方面的内容。 首先,我们可以探讨不透明制品的性质。不透明制品具有阻挡光线透过的特性,因此我们无法透过它们看到内部的细节或物质。这种特性对于一些需要保护隐私或防止露出的物品非常重要。此外,不透明制品还可能具有一定的硬度、耐磨性和抗腐蚀性能。 其次,我们可以讨论不透明制品的生产工艺。不透明制品的生产通常涉及到原料的选取、加工和成型等过程。例如,陶瓷制品的生产需要选取合适的陶土,经过成型、干燥、烧结等步骤。金属制品的生产则涉及到金属矿石的提取、冶炼、铸造或加工等过程。 最后,我们可以探讨不透明制品的应用领域。不透明制品在日常生活中广泛应用。例如,陶瓷制品常用于餐具、装饰品和建筑材料等领域;金属制品广泛应用于机械、电子、建筑和汽车等行业;塑料制品则应用于包装、家居用品和工业制品等方面。 总结起来,2023年华数杯的B题关于不透明制品,可能会涉及到不透明制品的性质、生产工艺和应用领域等方面的内容。我们需要对不透明制品有所了解,并结合具体的知识和经验来应对这道题目。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值