【AcWing】蓝桥杯集训每日一题Day1|二分|差分|503.借教室(C++)

503. 借教室

503. 借教室 - AcWing题库
难度:简单
时/空限制:1s / 128MB
总通过数:8052
总尝试数:26311
来源:NOIP2012提高组
算法标签二分差分

题目内容

在大学期间,经常需要租借教室。
大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。
教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。 
面对海量租借教室的信息,我们自然希望编程解决这个问题。
我们需要处理接下来 n n n天的借教室信息,其中第 i i i天学校有 r i r_{i} ri个教室可供租借。
共有 m m m份订单,每份订单用三个正整数描述,分别为 d j , s j , t j d_{j},s_{j},t_{j} dj,sj,tj表示某租借者需要从第 s j s_{j} sj天到第 t s t_{s} ts天租借教室(包括第 s j s_{j} sj天和第 t j t_{j} tj天),每天需要租借 d j d_{j} dj个教室。 
我们假定,租借者对教室的大小、地点没有要求。
即对于每份订单,我们只需要每天提供 d j d_{j} dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。
借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。
如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。
这里的无法满足指从第 s j s_{j} sj天到第 t j t_{j} tj天中有至少一天剩余的教室数量不足 d j d_{j} dj个。 
现在我们需要知道,是否会有订单无法完全满足。
如果有,需要通知哪一个申请人修改订单。

输入格式

第一行包含两个正整数 n , m n,m n,m,表示天数和订单的数量。 
第二行包含 n n n个正整数,其中第 i i i个数为 r i r_{i} ri,表示第 i i i天可用于租借的教室数量。 
接下来有 m m m行,每行包含三个正整数 d j , s j , t j d_{j},s_{j},t_{j} dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。 
每行相邻的两个数之间均用一个空格隔开。
天数与订单均用从 11 开始的整数编号。

输出格式

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

数据范围

1 ≤ n , m ≤ 1 0 6 1≤n,m≤10^6 1n,m106
0 ≤ r i , d j ≤ 1 0 9 0≤r_{i},d_{j}≤10^9 0ri,dj109
1 ≤ s j ≤ t j ≤ n 1≤s_{j}≤t_{j}≤n 1sjtjn

输入样例:
4 3
2 5 4 3
2 1 3
3 2 4
4 2 4
输出样例:
-1
2
题目解析

数据范围在 1 0 6 10^6 106,时间复杂度要控制在 O ( n log ⁡ n ) O(n\log n) O(nlogn)/ O ( n ) O(n) O(n)
如何通过数据范围判断时间复杂度可以参考这篇文章
蓝桥杯暴力求解与高频考点-CSDN博客
如果直接模拟,不优化的话
![[Pasted image 20240309164127.png]]

可以从前往后依次遍历每个订单,可以开个数组,统计一下每一天一共需要多少教室
s … t s \dots t st天,每天需要 d d d个教室,可以枚举for循环一下,从s~t枚举一遍,cnt[i]+=d,每次加完之后,判断这一天需要教室数量是不是小于给定教室数量,如果是的话,表示满足;不是的话,表示不满足。
一共需要处理 1 0 6 10^6 106个订单,每个订单的区间长度最大 O ( n ) = 1 0 6 O(n)=10^6 O(n)=106,时间复杂度就是 1 0 6 ∗ 1 0 6 = 1 0 12 10^6*10^6=10^{12} 106106=1012,肯定会TLE(Time Limit Exceeded时间超限)。
如果代码不想超时,需要将时间复杂度控制在 1 0 8 10^8 108以内(1s是 1 0 8 10^8 108)

优化的话
如果按照题意进行动态地做,动态地给每一个区间加上同一个d,然后再去动态地判断这个区间内的某一个值是不是大于给定的值。

可以用线段树来做,可是线段树时间复杂度比较高,可能会TLE,线段树的题目n一般会给到 1 0 5 10^5 105。要使用比线段树常数更小的算法

1. 差分

如果把这个题变成一个判定性的问题,
判断一下能不能处理前k个订单,这个时候,这个题目就变成了给k个区间,每个区间加一个相同的数,加完之后需要计算一下每个数最终的值是多少
![[Pasted image 20240309164206.png]]

经典的模板题,相当于算法里的公式
797.差分
有一个标准做法,可以做到线性的时间复杂度 O ( n + m ) O(n+m) O(n+m)
判定性问题可以用差分来做

差分的原理

比如每一天可以用的教室数量是 r 1 … r n r_{1}\dots r_{n} r1rn,用数组r表示
要统计一下每天需要多少教室 a 1 … a n a_{1}\dots a_{n} a1an,用a数组来表示
初始的时候都是0,
给一个s~t的订单,给 a s … a t a_{s}\dots a_{t} asat之间的每个数全部加上一个d
先将a数组进行一个变形
a 0 = 0 a_{0}=0 a0=0
b 1 = a 1 − a 0 b_{1}=a_{1}-a_{0} b1=a1a0 b 2 = a 2 − a 1 b_{2}=a_{2}-a_{1} b2=a2a1以此类推,一直到 b n = a n − a n − 1 b_{n}=a_{n}-a_{n-1} bn=anan1
相当于对a数组进行一个差分变换
发现
如果给我们一个差分数组b,可以把原数组a反推回来
给原数组a,可以把差分数组b求出来
差分数组和原数组的信息量是一模一样的
差分数组推原数组
a 1 = b 1 + a 0 = b 1 a_{1}=b_{1}+a_{0}=b_{1} a1=b1+a0=b1
a 2 = b 2 + a 1 = b 1 + b 2 a_{2}=b_{2}+a_{1}=b_{1}+b_{2} a2=b2+a1=b1+b2
a n = b n + a n − 1 = b 1 + ⋯ + b n a_{n}=b_{n}+a_{n-1}=b_{1}+\dots+b_{n} an=bn+an1=b1++bn
原数组就是差分数组的前缀和数组

转换完之后
如果想对s~t,每个数加上一个d的话
如果要对原数组操作,要去修改 O ( n ) O(n) O(n)个数
但是这个操作对差分数组的影响就很少了
b 1 = a 1 − a 2 b 2 = a 2 − a 1 … b s − 1 = a s − 1 − a s − 2 b s = a s − a s − 1 b s + 1 = a s + 1 − a s … b t = a t − a t − 1 b t + 1 = a t + 1 − a t b t + 2 = a t + 2 − a t + 1 … \begin{array}{} b_{1}=a_{1}-a_{2} \\ b_{2}=a_{2}-a_{1} \\ \dots \\ b_{s-1}=a_{s-1}-a_{s-2} \\ b_{s}=a_{s}-a_{s-1} \\ b_{s+1}=a_{s+1}-a_{s} \\ \dots \\ b_{t}=a_{t}-a_{t-1} \\ b_{t+1}=a_{t+1}-a_{t} \\ b_{t+2}=a_{t+2}-a_{t+1} \\ \dots \end{array} b1=a1a2b2=a2a1bs1=as1as2bs=asas1bs+1=as+1asbt=atat1bt+1=at+1atbt+2=at+2at+1
这个操作只会对 a s … a t a_{s}\dots a_{t} asat将每个数全部加上d
因此
b 1 … b s − 1 b_{1}\dots b_{s-1} b1bs1都是不变的,因为 a 0 … a s − 1 a_{0}\dots a_{s-1} a0as1不变,所以差值也不变
b s b_{s} bs的话, a s a_{s} as加上一个d, a s − 1 a_{s-1} as1不变,所以 b s b_{s} bs加了一个d
b s + 1 … b t b_{s+1}\dots b_{t} bs+1bt,由于 a s … a t a_{s}\dots a_{t} asat每个数全部加了一个d,所以差值是不变的,所以b都是不变的
b t + 1 b_{t+1} bt+1的话, a t + 1 a_{t+1} at+1不变, a t a_{t} at加了一个d,所以差值会减一个d,所以 b t + 1 b_{t+1} bt+1减一个d
b t + 2 b_{t+2} bt+2开始到后面的,因为从 a t + 1 … a n a_{t+1}\dots a_{n} at+1an一直都不变,所以不变
不变 { b 1 = a 1 − a 2 b 2 = a 2 − a 1 … b s − 1 = a s − 1 − a s − 2 + d b s = a s − a s − 1 不变 { b s + 1 = a s + 1 − a s … b t = a t − a t − 1 − d b t + 1 = a t + 1 − a t 不变 { b t + 2 = a t + 2 − a t + 1 … \begin{array}{} \\ 不变\begin{cases} b_{1}=a_{1}-a_{2} \\ b_{2}=a_{2}-a_{1} \\ \dots \\ b_{s-1}=a_{s-1}-a_{s-2} \\ \end{cases}\\ +d\qquad b_{s}=a_{s}-a_{s-1} \\ 不变\begin{cases} b_{s+1}=a_{s+1}-a_{s} \\ \dots \\ b_{t}=a_{t}-a_{t-1} \\ \end{cases}\\ -d\qquad b_{t+1}=a_{t+1}-a_{t} \\ 不变\begin{cases} b_{t+2}=a_{t+2}-a_{t+1} \\ \dots \end{cases} \end{array} 不变 b1=a1a2b2=a2a1bs1=as1as2+dbs=asas1不变 bs+1=as+1asbt=atat1dbt+1=at+1at不变{bt+2=at+2at+1

对于原数组的操作,本来要操作 O ( n ) O(n) O(n)个数,对于差分数组的影响,只会影响 b s b_{s} bs b t + 1 b_{t+1} bt+1两个数,这样就可以将修改操作从 O ( n ) O(n) O(n)变成 O ( 1 ) O(1) O(1)
改变 O ( n ) O(n) O(n)个数,需要两层循环,现在只用改变两个数,就不用写循环了,可以把时间复杂度从 O ( n 2 ) O(n^2) O(n2)变成 O ( n ) O(n) O(n)
这样的话每个操作就不要对原数组操作,而是对差分数组进行操作,差分数组求完之后,再通过差分数组求出来原数组,相当于做一个变换

这样可以用 O ( n + m ) O(n+m) O(n+m)的时间复杂度,判断出前k个订单有没有出现矛盾

2. 二分

原问题
把所有的订单取出来,编号是1~m
先到先得,按照编号顺序依次处理每个订单

二段性

这些个能处理的订单,有一个二段性
比如说在这个问题里面,第k个订单是最后一个能处理的订单
从第k+1个订单开始就不能处理了
![[Pasted image 20240309185859.png]]

把前k个区间全部加到数组上,每一天需要的教室数量都是小于等于给定的教室数量,对于k前面的任何一个数x,同样能处理x个订单,显然是成立的
前x个订单严格比前k个订单少一些区间,相当于在某些数上少加了一些d,加上那些之后不会超过给定值,不加那些数同样不会超过给定值
最后一个能处理的订单是第k个订单的话,对于小于等于k等任何一个数x,前x个订单一定都是可以处理的

同理

第一个不能处理的订单是第k+1个订单的话,如果把前k+1个区间加到天数数组r上的话,一定会有某一天,它需要的教室数量大于给定值
对于大于等于k+1的任何一个x,1~x一定也都是不能处理的
![[Pasted image 20240309185935.png]]

因为前k+1个区间加完之后,在某一天已经大于给定值了,再加上一些额外的数,仍然会大于给定值


对于x来说,当x取1~k之间的数的时候,它是满足的
当x大于k的时候,是不满足的

具有二段性的话,就可以通过二分把这个边界二分出来,
789.数的范围

如何二分

比如最后一个能处理的订单是第k个订单,
左右边界是1~m
每次二分一个中点mid
如果1~mid,能满足的话,说明最后一个能满足的订单在mid或者在mid的右边,所以答案会落在 [ m i d , m ] [mid,m] [mid,m]这个区间,
![[Pasted image 20240309191741.png]]

就可以删掉左边的区间,把二分的左端点L设成mid
![[Pasted image 20240309191817.png]]

再二分中点
取一个mid,如果处理mid这个订单会出现矛盾,说明1~mid是无法处理的,说明最后一个能处理的订单在mid的严格左边
![[Pasted image 20240309190835.png]]

因此相当于把右边的区间删掉,把右端点R置成mid-1
![[Pasted image 20240309190918.png]]

每次将搜索范围缩小一半,缩小完之后保证答案一定在搜索范围内,最后当范围内只有一个数的时候,它就是答案

二分模板用哪个,取决于mid属于左半边区间还是右半边区间,取整的问题,二分的话,整数不一定能够刚好整除,奇数的话是上取整还是下取整,如果模板用错可能会有死循环

代码
#include <iostream>
#include <cstring>
#include <algorithm>using namespace std;typedef long long LL;
//算前缀和,10^6个10^9,有可能会爆int,需要用到long longconst int N = 1000010;int n, m;
int w[N];
//用w存r,不用r,因为二分的时候会用到变量r,防止变量冲突
int d[N], s[N], t[N];
LL b[N];//检查前mid订单能不能满足
bool check (int mid)
{memset(b, 0, sizeof b); //先把差分数组初始化为0,不能让上次检查的结果,影响下次检查的过程for (int i = 1; i <= mid; i++) //依次处理每一个订单{b[s[i]] += d[i];b[t[i] + 1] -= d[i];}LL s = 0;  //用一个前缀和来计算当前的每一a_i是多少for (int i = 1; i <= n; i++) //以此类推每一天{s += b[i]; //每次更新一下前缀和if (s > w[i]) return false;  //发现当前教室数量大于给定教室数量,return false}return true;  //否则return true
}int main()
{scanf("%d%d", &n, &m);for (int 1 = 1; i <= n; i++) scanf("%d", &w[i]);//依次读入每天可以用的教室数量for (int i = 1; i <= m; i++) scanf("%d%d%d", &d[i], &s[i], &t[i]);//依次读入m个订单d,s,t,订单数量和起始时间//二分int l = 0; r = m;   //0表示一个订单都不能满足while (l < r){//求中点int mid = l + r + 1 >> 1; //因为l=mid,+1用上取整;如果r=mid,用下取整if (check(mid)) l = mid;  //如果发现[1,mid)可以满足,表示答案应该在[mid,m]else r = mid -1;}if (r == m) puts("0"); //如果发现所有订单都能满足,输出0else printf("-1\n%d\n", r + 1); //否则第一行输出-1,第二行输出第一个不能满足的订单编号return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/733540.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于机器学习的网络入侵检测二元分类模型构建与性能评估(NSL-KDD数据集)

简介 该项目是一个基于NSL-KDD数据集的网络入侵检测系统&#xff0c;主要采用机器学习方法对网络流量数据进行使用了多种机器学习模型&#xff0c;如逻辑回归、线性SVM、多项式核SVM、高斯核SVM、决策树、随机森林、朴素贝叶斯和K近邻算法训练二元分类&#xff08;正常/异常&a…

bug总结(1)--变量取错

a c t i v i t y [ ′ t a g n a m e ′ ] 应为 activity[tag_name]应为 activity[′tagn​ame′]应为couponActivitList[0][‘name’] .隐藏的bug&#xff0c;在测试中竟然测不出来&#xff0c;而且上线了好久。为啥会出现这种低级错误呢&#xff1f;第一是写的时候不够仔细认…

Day26:安全开发-PHP应用模版引用Smarty渲染MVC模型数据联动RCE安全

目录 新闻列表 自写模版引用 Smarty模版引用 代码RCE安全测试 思维导图 PHP知识点&#xff1a; 功能&#xff1a;新闻列表&#xff0c;会员中心&#xff0c;资源下载&#xff0c;留言版&#xff0c;后台模块&#xff0c;模版引用&#xff0c;框架开发等 技术&#xff1a;输…

2024 年中国高校大数据挑战赛赛题 C:用户对博物馆评论的情感分析完整思路以及源代码分享

博物馆是公共文化服务体系的重要组成部分。国家文物局发布&#xff0c; 2021 年我国新增备案博物馆 395 家&#xff0c;备案博物馆总数达 6183 家&#xff0c;排 名全球前列&#xff1b;5605 家博物馆实现免费开放&#xff0c;占比达 90%以上&#xff1b;全国 博物馆举办展览 3…

【深度学习笔记】6_5 RNN的pytorch实现

注&#xff1a;本文为《动手学深度学习》开源内容&#xff0c;部分标注了个人理解&#xff0c;仅为个人学习记录&#xff0c;无抄袭搬运意图 6.5 循环神经网络的简洁实现 本节将使用PyTorch来更简洁地实现基于循环神经网络的语言模型。首先&#xff0c;我们读取周杰伦专辑歌词…

Python操作Redis 各种数据类型

本文将深入探讨如何使用Python操作Redis&#xff0c;覆盖从基础数据类型到高级功能的广泛主题。无论是字符串、列表、散列、集合还是有序集合&#xff0c;我们将一一解析&#xff0c;同时提供丰富的代码示例帮助读者更好地理解和应用。除此之外&#xff0c;本文还将介绍Redis的…

【20240309】WORD宏设置批量修改全部表格格式

WORD宏设置批量修改全部表格格式 引言1. 设置表格文字样式2. 设置表格边框样式3. 设置所有表格边框样式为075pt4. 删除行参考 引言 这两周已经彻底变为office工程师了&#xff0c;更准确一点应该是Word工程师&#xff0c;一篇文档动不动就成百上千页&#xff0c;表格图片也是上…

STM32之串口中断接收UART_Start_Receive_IT

网上搜索了好多&#xff0c;都是说主函数增加UART_Receive_IT()函数来着&#xff0c;实际正确的是UART_Start_Receive_IT()函数。 —————————————————— 参考时间&#xff1a;2024年3月9日 Cube版本&#xff1a;STM32CubeMX 6.8.1版本 参考芯片&#xff1a…

Svg Flow Editor 原生svg流程图编辑器(二)

系列文章 Svg Flow Editor 原生svg流程图编辑器&#xff08;一&#xff09; 说明 这项目也是我第一次写TS代码哈&#xff0c;现在还被绕在类型中头昏脑胀&#xff0c;更新可能会慢点&#xff0c;大家见谅~ 目前实现的功能&#xff1a;1. 元件的创建、移动、形变&#xff1b;2…

【C语言】字符指针

在指针的类型中我们知道有一种指针类型为字符指针char* 一般使用&#xff1a; int main() { char ch w; char *pc &ch; *pc w; return 0; } 还有一种使用方式&#xff0c;如下&#xff1a; int main() { const char* pstr "hello bit.";//这⾥是把⼀个字…

plantUML使用指南之序列图

文章目录 前言一、序列图1.1 语法规则1.1.1 参与者1.1.2 生命线1.1.3 消息1.1.4 自动编号1.1.5 注释1.1.6 其它1.1.7 例子 1.2 如何画好 参考 前言 在软件开发、系统设计和架构文档编写过程中&#xff0c;图形化建模工具扮演着重要的角色。而 PlantUML 作为一种强大且简洁的开…

【stm32 外部中断】

中断&#xff1a;在主程序运行过程中&#xff0c;出现了特定的中断触发条件&#xff08;中断源&#xff09;&#xff0c;使得CPU暂停当前正在运行的程序&#xff0c;转而去处理中断程序&#xff0c;处理完成后又返回原来被暂停的位置继续运行 中断优先级&#xff1a;当有多个中…

LoadBalancer (本地负载均衡)

1.loadbalancer本地负载均衡客户端 VS Nginx服务端负载均衡区别 Nginx是服务器负载均衡&#xff0c;客户端所有请求都会交给nginx&#xff0c;然后由nginx实现转发请求&#xff0c;即负载均衡是由服务端实现的。 loadbalancer本地负载均衡&#xff0c;在调用微服务接口时候&a…

考研复习C语言初阶(4)+标记和BFS展开的扫雷游戏

目录 1. 一维数组的创建和初始化。 1.1 数组的创建 1.2 数组的初始化 1.3 一维数组的使用 1.4 一维数组在内存中的存储 2. 二维数组的创建和初始化 2.1 二维数组的创建 2.2 二维数组的初始化 2.3 二维数组的使用 2.4 二维数组在内存中的存储 3. 数组越界 4. 冒泡…

【Java JVM】Class 文件的加载

Java 虚拟机把描述类的数据从 Class 文件加载到内存, 并对数据进行校验, 转换解析和初始化, 最终形成可以被虚拟机直接使用的 Java 类型, 这个过程被称作虚拟机的类加载机制。 与那些在编译时需要进行连接的语言不同, 在 Java 语言里面, 类的加载, 连接和初始化过程都是在程序…

解决阿里云服务器开启frp服务端,内网服务器开启frp客户端却连接不上的问题

解决方法&#xff1a; 把阿里云自带的Alibabxxxxxxxlinux系统 换成centos 7系统&#xff01;&#xff01;&#xff01;&#xff01; 说一下我的过程和问题&#xff1a;由于我们内网的服务器在校外是不能连接的&#xff0c;因此我弄了个阿里云服务器做内网穿透&#xff0c;所谓…

大模型学习过程记录

一、基础知识 自然语言处理&#xff1a;能够让计算理解人类的语言。 检测计算机是否智能化的方法&#xff1a;图灵测试 自然语言处理相关基础点&#xff1a; 基础点1——词表示问题&#xff1a; 1、词表示&#xff1a;把自然语言中最基本的语言单位——词&#xff0c;将它转…

你应该打好你的日志,起码避免被甩锅

大家好&#xff0c;我是蓝胖子,相信大家或多或少都有这样的经历&#xff0c;当你负责的功能出现线上问题时&#xff0c;领导第一时间便是找到你询问原因&#xff0c;然而有时问题的根因或许不在你这儿&#xff0c;只是这个功能或许依赖了第三方或者内部其他部门&#xff0c;这个…

【Unity InputSystem】实用指南:在PC端(鼠标与键盘)、手机端(触摸屏)、主机手柄上同步实现角色移动与跳跃功能

前引 随着Unity的不断发展&#xff0c;开发者对于项目的输入系统要求也日益提高。在进行多平台适配和跨平台移植时&#xff0c;常常需要改变输入系统&#xff0c;这给开发者带来了不少困扰。而Unity官方推出的InputSystem插件&#xff0c;则是为了解决这一问题而推出的全新输入…

Linux内存管理--系列文章壹

一、引子 作者、我在上班闲着没事的时候&#xff0c;看了一些关于Linux内存管理和程序装载、链接的文章&#xff0c;然后自己就总结出了一些东西。 本系列文章一方面将资料中的长篇大论总结到最少、以方便可以直接找到答案&#xff0c;一方面也是方便面试的时候可以吹牛逼。 L…