蓝桥杯2023年第十四届省赛真题-冶炼金属(二分法)

本文介绍了如何解决一道关于冶炼金属的编程问题,通过转化率V的计算和二分查找策略,确定在给定N组独立数据下的最小和最大转化率。作者详细解析了暴力法和二分法的应用,并给出了C语言的完整代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

*个人学习及思路记录,含个人浅薄理解,可供参考。

题目:

蓝桥杯2023年第十四届省赛真题-冶炼金属 - C语言网 (dotcpp.com)

题目分析

  1. 关键词:转化率V,原料数A,产物数B,N组独立数据;
  2. 题目翻译:对于单组数据:Bi = \frac{Ai}{Vi},可得整数Vi取值范围[Vimin,Vimax]。
    对N组Vi取交集得到合法V,即合法V对所有A与B应满足:B=\frac{A}{V},V取值范围[Vmin,Vmax]。Vmin、Vmax即为题目所求。
  3. PS:除法默认向下取整(结果是某一整数定值),但本题中V明显是要取一整数范围的未知数,因此Bi = \frac{Ai}{Vi}这里不能简单等价于Vi = Bi/Ai,正确思路后面有详细解析。
  4. 转编程思维:
    (暴力法):按上述翻译,对所有求得的Vmin、Vmax求交集(因为题目保证有解,所以求max{Vimin}、min{Vimax})。

二分法思路:

“合法V对所有A与B应满足:B=\frac{A}{V},V取值范围[Vmin,Vmax]”
《==》对所有合法V,满足Bi\leq \frac{Ai}{V}< Bi+1(此处除法取整)

《==》对所有合法V,满足\frac{Ai}{Bi+1}\leq V\leq \frac{Ai}{Bi}(此处除法取整)

《==》对[Vmin,Vmax],一定满足\frac{Ai}{Bi+1} +1\leq Vmin\leq Vmax\leq \frac{Ai}{Bi}(此处除法取整

******注意左边界是\frac{Ai}{Bi+1} +1而不是\frac{Ai}{Bi+1}*******

得到如下区间图:

问题拆解与具体分析:

  1. 求Vmin:
    对V<Vmin,由交集思维,至少有一组数据不满足V\geq \frac{Ai}{Bi+1} +1,即至少有一组数据满足V< \frac{Ai}{Bi+1} +1(以下除法均取整);
    对V>=Vmin,所有V满足V\geq \frac{Ai}{Bi+1} +1
    由此得出循环终止条件与if-else分类标准:
    while (lmin < rmin) {
    	for (int i = 0; i < n; i++) {
    		if (mid < a[i]/(b[i]+1)+1) {
    			lmin = mid + 1;
    			flag = 1;  //标记,该mid处于min左侧
    			break;
    		}
    	}
    	if (!flag) {
    		//mid处于min右侧,则执行
    		rmin = mid;
    	}
    	mid = lmin + rmin >> 1;
    	flag = 0;   //刷新flag
    }
    flag = 0;
    }
  2. 求Vmax同理。
    while (lmax < rmax) {
    	for (int i = 0; i < n; i++) {
    		if (mid > a[i]/b[i]) {
    			rmax = mid -1;
    			flag = 1;   //标记,该mid处于max右侧
    			break;
    		}
    	}
    	if (!flag) {
    		//mid处于max左侧,则执行
    		lmax = mid;
    	}
    	mid = lmax + rmax + 1>> 1;
    	flag = 0;
    }

    tips:
    是否进行+-1修正和不等式是否取等同步(恰好取等时不能进行修正);
    修正时Vmin可由小趋大、Vmax可由大趋小,因此求Vmax的时候mid = lmax + rmax + 1>> 1,否则可能会出现某一步lmax正好取max-1而无法进行修正、进入死循环的情况。

完整代码:


/*
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。
这个炉子有一个称作转换率的属性 V,V 是一个正整数,这意味着消耗 V 个普通金属 O
恰好可以冶炼出一个特殊金属 X,当普通金属 O 的数目不足 V 时,无法继续冶炼。
现在给出了 N 条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了
A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。每条记录都是独立的,
这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。
根据这 N 条冶炼记录,请你推测出转换率 V 的最小值和最大值分别可能是多少,
题目保证评测数据不存在无解的情况。
*/
//#include <bits/stdc++.h>
#include<iostream>
#include<vector>

#define ll long long
#define endl '\n'

using namespace std;


void solve() {
	int n;
	cin >> n;
	vector<ll>a(n), b(n);
	for (int i = 0; i < n; i++) {
		cin >> a[i] >> b[i];
	}
	//  输入

	ll lmin = 1; ll rmin = 1e9;
	ll mid = lmin + rmin >> 1; 
	int flag = 0;
	while (lmin < rmin) {
		for (int i = 0; i < n; i++) {
			if (mid < a[i]/(b[i]+1)+1) {
				lmin = mid + 1;
				flag = 1;  //标记,该mid处于min左侧
				break;
			}
		}
		if (!flag) {
			//mid处于min右侧,则执行
			rmin = mid;
		}
		mid = lmin + rmin >> 1;
		flag = 0;   //刷新flag
	}
	flag = 0;
	// 处理min

	ll lmax = 1; ll rmax = 1e9;
	mid = lmax + rmax + 1>> 1;
	while (lmax < rmax) {
		for (int i = 0; i < n; i++) {
			if (mid > a[i]/b[i]) {
				rmax = mid -1;
				flag = 1;   //标记,该mid处于max右侧
				break;
			}
		}
		if (!flag) {
			//mid处于max左侧,则执行
			lmax = mid;
		}
		mid = lmax + rmax + 1>> 1;
		flag = 0;
	}
	//  处理max

	cout  << lmin << ' '<< lmax;
	//  输出
}




int main() {
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);

	solve();
	return 0;
}

吐槽:蓝桥杯真题初尝试,每一条说明背后都是一个坑......明明是简单的一道题但感觉自己把所有的坑全栽了一遍......

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值