洛谷 P1083 借教室 (二分+差分数组)

题目连接

    题意:
            处理 n 天的借教室信息, 第 i 天学校有 ri个教室可以租
            m 份订单,每份订单有三个整数, d, s, t
            【s, t】天租借教室 每天租 d个教室
            借教室原则先到先得,如果遇到一份订单无法满足,停止分配
            通知申请人修改订单,(无法满足:从s, 到 t 天中至少有一天剩余的教室不足d个)
            求是否有订单无法完全满足, 如果有通知哪个申请人      
    思路: 
            数据范围  n ,m 1e6, (0<= r, d <= 1e9),(1 <= s, t <= n) 
            1)区间更新,每次更新都要+ 判断,
            2)判断每个点是否有负值,如果有负值,输出需要修改订单的申请人编号 
            3)用线段树  
            4) 差分数组
    关于二分:
            关于答案二分一般来说,二分是个很有用的优化途径,
            因为这样会直接导致减半运算,而对于能否二分,
            有一个界定标准:
                状态的决策过程或者序列是否满足单调性或者可以局部舍弃性。 
                而在这个题里,因为如果前一份订单都不满足,
                那么之后的所有订单都不用继续考虑;
                而如果后一份订单都满足,那么之前的所有订单一定都可以满足,
                符合局部舍弃性,所以可以二分订单数量。

AC:

/*
	题意:
			处理 n 天的借教室信息, 第 i 天学校有 ri个教室可以租
			m 份订单,每份订单有三个整数, d, s, t
			【s, t】天租借教室 每天租 d个教室
			借教室原则先到先得,如果遇到一份订单无法满足,停止分配
			通知申请人修改订单,(无法满足:从s, 到 t 天中至少有一天剩余的教室不足d个)
			求是否有订单无法完全满足, 如果有通知哪个申请人 	 
	思路: 
			数据范围  n ,m 1e6, (0<= r, d <= 1e9),(1 <= s, t <= n) 
			1)区间更新,每次更新都要+ 判断,
			2)判断每个点是否有负值,如果有负值,输出需要修改订单的申请人编号 
			3)用线段树  
			4) 差分数组
	关于二分:
			关于答案二分一般来说,二分是个很有用的优化途径,
			因为这样会直接导致减半运算,而对于能否二分,
			有一个界定标准:
				状态的决策过程或者序列是否满足单调性或者可以局部舍弃性。 
				而在这个题里,因为如果前一份订单都不满足,
				那么之后的所有订单都不用继续考虑;
				而如果后一份订单都满足,那么之前的所有订单一定都可以满足,
				符合局部舍弃性,所以可以二分订单数量。
		 
*/
#include<iostream>
#include<cstring>
#include<algorithm>
#include<stdio.h>
using namespace std;
typedef long long ll;
const int maxn = 1e6;
int N, M; 
int Rest[maxn + 10];
int F[maxn + 10];
//int Need[maxn + 10];
struct node{
	int L, R;
	int d;
}Inter[maxn + 10];
bool Solve(int x) {
	bool flag = 1;
	memset(F, 0, sizeof(F));
	for(int i = 1; i <= x; ++i) {
		F[Inter[i].L] += Inter[i].d;
		F[Inter[i].R + 1] -= Inter[i].d;
	}
	int Temp = 0;
	for(int i = 1; i <= N; ++i) {
		Temp += F[i];
		if(Temp > Rest[i]){
			flag = 0;
			break;
		} 
	} 
	return flag;
} 
int main() {
	//freopen("in.txt", "r", stdin);
	scanf("%d%d", &N, &M);
	for(int i = 1; i <= N; ++i) {
		scanf("%d", &Rest[i]);
		F[i] = Rest[i] - F[i-1];
	}
	int d, s, t;
	for(int i = 1; i <= M; ++i) {
		scanf("%d%d%d", &Inter[i].d, &Inter[i].L, &Inter[i].R);
	}
	if(Solve(M)) {
		printf("0");
		return 0;
	}
	int left = 1, right = M;
	while(left < right) {
		int mid = (left + right) / 2;
		if (Solve(mid)) 
			left = mid + 1;
		else 
			right = mid;
	}
	printf("-1\n");
	printf("%d", left);
	return 0;
}
发布了199 篇原创文章 · 获赞 156 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/Harington/article/details/100866033
今日推荐