二分(蓝桥备赛)

文章介绍了解决借教室问题的编程方法,涉及资源分配策略和查找最大满足条件,以及巧克力切分和金属冶炼中的最小最大转换率计算。
摘要由CSDN通过智能技术生成

1、借教室(NOIP2012提高组)
问题描述
在大学期间,经常需要租借教室。

大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。

教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。 

面对海量租借教室的信息,我们自然希望编程解决这个问题。

我们需要处理接下来 n 天的借教室信息,其中第 i 天学校有 ri 个教室可供租借。

共有 m 份订单,每份订单用三个正整数描述,分别为 dj,sj,tj,表示某租借者需要从第 sj 天到第 tj 天租借教室(包括第 sj天和第 tj天),每天需要租借 dj 个教室。 

我们假定,租借者对教室的大小、地点没有要求。

即对于每份订单,我们只需要每天提供 dj 个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。 

借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。

如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。

这里的无法满足指从第 sj天到第 tj 天中有至少一天剩余的教室数量不足 dj 个。 

现在我们需要知道,是否会有订单无法完全满足。

如果有,需要通知哪一个申请人修改订单。

输入格式
第一行包含两个正整数 n,m,表示天数和订单的数量。 

第二行包含 n个正整数,其中第 i 个数为 ri,表示第 i 天可用于租借的教室数量。 

接下来有 m行,每行包含三个正整数 dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。 

每行相邻的两个数之间均用一个空格隔开。

天数与订单均用从 11 开始的整数编号。

输出格式
如果所有订单均可满足,则输出只有一行,包含一个整数 00。

否则(订单无法完全满足)输出两行,第一行输出一个负整数 −1−1,第二行输出需要修改订单的申请人编号。

数据范围
1≤n,m≤1e6
0≤ri,dj≤1e9
1≤sj≤tj≤n

输入样例:
4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
输出样例:
-1
2

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int N=1e6+10;
typedef long long ll;
ll n,m;
ll r[N],d[N],s[N],t[N],b[N];
bool check(ll m)
{
	memset(b,0,sizeof(b)); 
	for(int i=1;i<=m;i++)
	{
		b[s[i]]+=d[i];//m份订单借教室已占情况 
		b[t[i]+1]-=d[i];//每过一天上一个订单的开始不占教室 
	}
	for(int i=1;i<=n;i++)
	{
		b[i]+=b[i-1];//重新分配教室 
		if(b[i]>r[i]) 
		{
			return false;
		}
	}
	return true;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		cin>>r[i];
	}
	for(int i=1;i<=m;i++)
	{
		cin>>d[i]>>s[i]>>t[i];
	}
	ll l=0,r=m,mid,ans;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(check(mid))
		{
			ans=mid;//满足单调性,假设有ans天满足 
			l=mid+1;//扩大范围 
		}
		else
		{
			r=mid-1;//缩小范围 
		}
	}
	if(ans==m)//二分到所有天数的教室都可以满足 
	{
		cout<<0<<endl;
	}
	else
	{
		cout<<-1<<endl<<r+1<<endl;//(r+1)==(mid-1)最先不满足的那天 
	}
	return 0;
}

 

2、分巧克力(第八届蓝桥杯 c++/java :A/B组)
儿童节那天有 K 位小朋友到小明家做客。

小明拿出了珍藏的巧克力招待小朋友们。

小明一共有 N 块巧克力,其中第 i 块是 Hi×Wi的方格组成的长方形。

为了公平起见,小明需要从这 N 块巧克力中切出 K 块巧克力分给小朋友们。

切出的巧克力需要满足:

形状是正方形,边长是整数
大小相同
例如一块 6×56×5 的巧克力可以切出 66 块 2×22×2 的巧克力或者 22 块 3×33×3 的巧克力。

当然小朋友们都希望得到的巧克力尽可能大,你能帮小明计算出最大的边长是多少么?

输入格式
第一行包含两个整数 N 和 K。

以下 N行每行包含两个整数 Hi 和 Wi。

输入保证每位小朋友至少能获得一块 1×11×1 的巧克力。

输出格式
输出切出的正方形巧克力最大可能的边长。

数据范围
1≤N,K≤1e5
1≤Hi,Wi≤1e5

输入样例:
2 10
6 5
5 6
输出样例:
2

 

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
const int n=1e5+10;
ll N,k;
ll h[n],w[n]; 
bool check(ll m)
{
	ll sum=0;
	for(int i=1;i<=N;i++)
	{
		sum+=(h[i]/m)*(w[i]/m);		
	}
	if(sum>=k) return true;
	else
	{
		return false;
	}
}
int main()
{
	cin>>N>>k;
	for(int i=1;i<=N;i++)
	{
		cin>>h[i]>>w[i];
	}
	ll l=0,r=n,mid,ans;
	while(l<=r)
	{
		mid=(l+r)/2;
		if(check(mid))
		{
			ans=mid;
			l=mid+1;
		}
		else
		{
			r=mid-1;
		}
	}
	cout<<ans<<endl;
	return 0;
}

3、管道(第十四届蓝桥杯 省赛 python B组)
有一根长度为 len 的横向的管道,该管道按照单位长度分为 len 段,每一段的中央有一个可开关的阀门和一个检测水流的传感器。

一开始管道是空的,位于 Li 的阀门会在 Si时刻打开,并不断让水流入管道。

对于位于 Li 的阀门,它流入的水在 Ti(Ti≥Si)时刻会使得从第 Li−(Ti−Si)段到第 Li+(Ti−Si) 段的传感器检测到水流。

求管道中每一段中间的传感器都检测到有水流的最早时间。

输入格式
输入的第一行包含两个整数 n,len用一个空格分隔,分别表示会打开的阀门数和管道长度。

接下来 n行每行包含两个整数 Li,Si用一个空格分隔,表示位于第 Li 段管道中央的阀门会在 Si 时刻打开。

输出格式
输出一行包含一个整数表示答案。

数据范围
对于 30% 的评测用例,n≤200,Si,len≤3000;
对于 70% 的评测用例,n≤5000,Si,len≤1e5;
对于所有评测用例,1≤n<=1e5,1≤Si,len≤1e9;

输入样例:
3 10
1 1
6 5
10 2
输出样例:
5
 

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll n,len;
ll l[100010],s[100010];
bool check(ll m)
{
	ll sum=0;
	ll last_l=1,last_r=1;
	for(ll i=0; i<n; i++)
	{
		if(m>=s[i])
		{
			sum++;
			ll left=l[i]-(m-s[i]);
			ll right=l[i]+(m-s[i]);
			if(last_l > left)
			{
				last_l=left;
				last_r=max(right,last_r);
			}
			else if(left <= last_r+1)
			{
				last_r = max(last_r, right);
			}
		}
	}
	if(sum==0)
	{
		return false;
	}
	if(last_l <= 1 && last_r>=len)
	{
		return true;
	}
	return false;
}
int main()
{
	cin>>n>>len;
	for(ll i=0; i<n; i++)
	{
		cin>>l[i]>>s[i];
	}
	ll L=0,R=2e9,mid,ans;
	while(L<=R)
	{
		mid=(L+R)/2;
		if(check(mid))
		{
			ans=L;
			R=mid-1;
		}
		else
		{
			L=mid+1;
		}
	}
	cout<<ans<<endl;
	return 0;
}

4.给定一个按照升序排列的长度为 n 的整数数组,以及 q个查询。

对于每个查询,返回一个元素 k 的起始位置和终止位置(位置从 00 开始计数)。

如果数组中不存在该元素,则返回 -1 -1。

输入格式
第一行包含整数 n 和 q,表示数组长度和询问个数。

第二行包含 n个整数(均在 1∼100001∼10000 范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式
共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1。

数据范围
1≤n≤100000
1≤q≤10000
1≤k≤10000

输入样例:
6 3
1 2 2 3 3 4
3
4
5
输出样例:
3 4
5 5
-1 -1

#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
typedef long long ll;
ll n,q,k;
ll a[100010];
vector<int>nums;
bool check(ll m)
{
	if(a[m]<=k)
	{
		return true;
	}
	else return false;
}
int main()
{
	cin>>n>>q;
	for(int i=0; i<n; i++)
	{
		cin>>a[i];
	}
	while(q--)
	{
		cin>>k;
		ll l=0,r=n,mid;
		nums.clear();
		while(l<=r)
		{
			mid=(l+r)/2;
			if(check(mid))
			{
				if(a[mid]==k)
				{
					nums.push_back(mid);
				}
				l=mid+1;
			}
			else
			{
				r=mid-1;
			}
		}
		if(nums.size()==0)
		{
			cout<<-1<<" "<<-1<<endl;
		}
		else
		{
			cout<<nums[0]<<" "<<nums[nums.size()-1]<<endl;
		}
	}
	return 0;
}

5、冶炼金属(第十四届蓝桥杯 省赛 C++ B组 )
小蓝有一个神奇的炉子用于将普通金属 O 冶炼成为一种特殊金属 X。

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

现在给出了 N条冶炼记录,每条记录中包含两个整数 A 和 B,这表示本次投入了 A 个普通金属 O,最终冶炼出了 B 个特殊金属 X。

每条记录都是独立的,这意味着上一次没消耗完的普通金属 O 不会累加到下一次的冶炼当中。

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

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

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

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

数据范围
对于 30%30% 的评测用例,1≤N≤1e2。
对于 60%60% 的评测用例,1≤N≤1e3。
对于 100%100% 的评测用例,1≤N≤1e4,1≤B≤A≤1e9。

输入样例:
3
75 3
53 2
59 2
输出样例:
20 25

#include<iostream>
using namespace std;
int main()
{
	int N,a,b;
	cin>>N;
	int max1=2e9,min1=0;
	while(N--)
	{
		cin>>a>>b;
		min1=max(min1,a/(b+1)+1);
		max1=min(max1,a/b);
	}
	cout<<min1<<" "<<max1<<endl;
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值