蓝桥OJ3510 冶炼金属(暴力+二分)

冶炼金属

学习了b站Turing_Sheep的思路

 

 一、暴力模拟

思路:

b[i] = a[i] / v

b[1] = a[1] / v

b[2] = a[2] / v

....

b[n] = a[n] / v

以上列举中v要满足所有的记录,但凡一个记录不满足,v就不满足题意。

从小到大列举v,设置v最大为1e6

设置一个标志位,如果不满足即跳过这个v

如果找到了满足所有记录的v,同时也是从小到大排列,肯定是最小的v

同理,从大到小排列找出最大的v

为什么这里的v取1e6?

因为要枚举所有的v,通过N条记录判断是否合法。

v: 1e4*N = 1e4*1e4 = 1e8(不超时,但是答案会有错误)

v: 1e6*N = 1e6*1e4 = 1e10 (会超时,但可以保证正确性)

#include<bits/stdc++.h>
using namespace std;
const int N = 1e4+10;

void solve()
{
	int n; cin >> n;
	vector<int>a(n),b(n);
	for (int i = 0; i < n; i++) cin >> a[i] >> b[i];
	
	//枚举的转化率v
	
	//从小到大枚举 找最小值 
	for (int i = 1; i <= 1e6; i++)
	{
		bool flag = true;//标记当前的v是否合法
		for (int j = 0; j < n; j++)
		{
			if (b[j] != (a[j] / i))
			{
				flag = false;
				break;		
			}	
		}
		if (flag)
		{
			cout << i << ' ';
			break;
		}
	} 
	//从大到小枚举 找最大值
	for(int i = 1e6; i >= 1; i--)
	{
		bool flag = true;
		for (int j = 0; j < n; j++)
		{
			if (b[j] != (a[j] / i))
			{
				flag = false;
				break;
			}
		}
		if (flag)
		{
			cout << i << '\n';
			break;
		}
	} 
}


signed main()
{
	ios::sync_with_stdio(0),cout.tie(0),cin.tie(0);
	int t;
	t = 1;
	while(t--)
	solve();
	return 0;
 } 
 

二、二分

思路:

将v的排列转化成从1到1e6的一条线,而我们要找的就是所有合法v的最大最小值。

对于min左侧的点,不包含min;至少存在一组数据,满足B[i] < A[i] / v

对于min右侧的点,不包含min;至少存在一组数据,满足B[i] >= A[i] / v

min这个点所对的v中对应的N条数据也是满足:B[i] >= A[i] / v

以上三条即check函数(找到我们需要的点,分析出该点左右两侧的性质)

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e4+10;
int a[N],b[N];
int n; 
bool check_min(int mid)
{
	for (int i = 0; i < n; i++)
	//至少存在一条数据是< 
		if (b[i] < a[i] / mid) return false;
		
	return true;
}

bool check_max(int mid)
{
	for (int i = 0; i < n; i++)
	//至少存在一条数据是< 
		if (b[i] > a[i] / mid) return false;
		
	return true;
}

signed main()
{
	cin >> n;
	for (int i = 0; i < n; i++) cin >> a[i] >> b[i];
	//	找最小值 
	int lmin = 1,rmin = 1e9;
	while(lmin < rmin){
		int mid = lmin + rmin >> 1;
		if (check_min(mid)) rmin = mid;
		else lmin = mid + 1;
	}
	//  找最大值
	int lmax = 1, rmax = 1e9;
	while(lmax < rmax){
		int mid = lmax + rmax + 1 >> 1;
		if(check_max(mid)) lmax = mid;
		else rmax = mid - 1;
	}
	cout << lmin << ' ' << lmax << '\n';
	return 0;
} 

 

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值