列表

详情


NC16564. [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,表示租借的数量,租借开始、结束分别在第几天。

每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。

输出描述

如果所有订单均可满足,则输出只有一行,包含一个整数0。否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。

示例1

输入:

4 3
2 5 4 3
2 1 3
3 2 4
4 2 4

输出:

-1
2

说明:

第1 份订单满足后,4 天剩余的教室数分别为0,3,2,3。
第2 份订单要求第2 天到第4 天每天提供3 个教室,而第3 天剩余的教室数为2,因此无法满足。分配停止,通知第2个申请人修改订单。

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 494ms, 内存消耗: 10220K, 提交时间: 2022-08-05 20:22:18

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int n,m;
int a[N],b[N],d[N],s[N],t[N];
int check(int x)
{
	for(int i=1; i<=n; i++)
	{
		b[i]=a[i]-a[i-1];
	}
	for(int i=1; i<=x; i++)
	{
		b[s[i]]-=d[i];
		b[t[i]+1]+=d[i];
	}
	int res=0;
	for(int i=1; i<=n; i++)
	{
		res+=b[i];
		if(res<0) return 1;
	}
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n; i++) cin>>a[i];
	for(int i=1; i<=n; i++) cin>>d[i]>>s[i]>>t[i];
	int l=1,r=m;
	while(l<r)
	{
		int mid=(l+r)/2;
		if(check(mid)) r=mid;
		else l=mid+1;
	}
	if(check(r)) cout<<-1<<endl<<r<<endl;
	else cout<<0<<endl;
	return 0;
}

C 解法, 执行用时: 236ms, 内存消耗: 12064K, 提交时间: 2021-06-22 18:00:10

#include<stdio.h>
int a[1000005],k1[1000005],l1[1000005],r1[1000005],b[1000005],c[1000005];
int main()
{
	int i,j,k,l,n,m,r,mid;
	scanf("%d%d",&n,&m);
	a[0]=0;
	for(i=1;i<=n;i++){
	scanf("%d",&a[i]);c[i]=a[i]-a[i-1];}
	for(i=1;i<=m;i++)scanf("%d%d%d",&k1[i],&l1[i],&r1[i]);
	l=1;r=m;
	while(l<=r){
		mid=(l+r)/2;
		for(i=1;i<=n;i++)b[i]=c[i];
		for(i=1;i<=mid;i++){
			b[l1[i]]-=k1[i];
			b[r1[i]+1]+=k1[i];
		}
		a[0]=0;
		for(i=1;i<=n;i++){
		a[i]=a[i-1]+b[i];
		if(a[i]<0)break;}
		if(i==n+1)
		l=mid+1;
		else
		r=mid-1;
	}
	if(l==m+1)
	printf("0");
	else
	printf("-1\n%d",l);
 } 

C++ 解法, 执行用时: 494ms, 内存消耗: 12152K, 提交时间: 2021-08-23 00:32:43

#include<bits/stdc++.h>
using namespace std;
namespace Acc{
	using ll=long long;
	const int N=1e6+9;
	int l[N],r[N],v[N],n,m,a[N];
	ll s[N];
	int chk(int x){
		memset(s,0,n+1<<3);
		for(int i=1;i<=x;++i)s[l[i]]+=v[i],s[r[i]+1]-=v[i];
		for(int i=1;i<=n;++i)if((s[i]+=s[i-1])>a[i])return 0;
		return 1;
	}
	void work(){
		int i,L,R,md;
		for(cin>>n>>m,L=i=1,R=m+1;i<=n;++i)cin>>a[i];
		for(i=1;i<=m;++i)cin>>v[i]>>l[i]>>r[i];
		while(L<R)if(chk(md=L+R>>1))L=md+1;else R=md;
		if(R==m+1)puts("0");else cout<<"-1\n"<<R<<'\n';
	}
}
int main(){return Acc::work(),0;}		

上一题