借教室与差分

原题

题目描述

在大学期间,经常需要租借教室。

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

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

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

我们需要处理接下来 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 开始的整数编号。

输出格式

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

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

数据范围

1≤n,m≤106,
0≤ri,dj≤109,
1≤sj≤tj≤n

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

借教室的订单,其实就是在每天需要教室数量的数组上进行一个区间的增减,可以用差分数组快速得到区间的变化,而又因为订单满足先来后到,即如果要处理第k个订单,必须保证从1到k-1号订单全部可以满足,那么就可以知道存在一个分界线:有最后一个能处理的订单x,在它之后的所有订单都不能处理,在它之前的所有订单都可以满足。那么就可以用二分去做。

差分数组:

bi是di相对于di-1的差值,通过差值我们也能计算出订单的需要教室数。如果有变化,就会在差分数组最左端+di,最右+1的位置-di,这就得到了教室数。

比如b1+2,b4-2,默认d0=0,那么d1相对d0多2,d1到d3不变,d4相对d3少2。

那么我们很容易得到结果,d0=0,d1~d3=2,d4=0,即在d1到d3这几天,我们每天都需要2个教室

代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>using namespace std;typedef long long LL;const int N=1e6+10;int n,m;
int w[N]; //第i天有wi个教室可供租借
int d[N],s[N],t[N];
LL b[N]; //差分数组bool check(int mid)
{memset(b,0,sizeof b); //每次检查,差分数组置零,防止上次操作影响//为什么这里不用计算差分数组初始值:b[i]=d[i]-d[i-1]? 注意,我们计算的是从1到mid的差分数组,mid每次都会变,如果不置零会导致上一次的差分数组影响这次的计算//bi是di相对于di-1的差值,通过差值我们也能计算出订单的需要教室数//如果有变化,就会在差分数组最左端+di,最右+1的位置-di,这就得到了教室数//比如b1+2,b4-2,默认d0=0,那么d1相对d0多2,d1到d3不变,d4相对d3少2//那么我们很容易得到结果,d0=0,d1~d3=2,d4=0,即在d1到d3这几天,我们每天都需要2个教室for(int i=1;i<=mid;i++) //从1号到mid号订单,用差分数组记录每天租借教室数量di{//si,ti表示第i份订单租借开始、结束的天数b[s[i]]+=d[i];b[t[i]+1]-=d[i]; //差分数组b,记录变化}LL s=0; //for(int i=1;i<=n;i++){s+=b[i]; //s相当于原数组,差分数组相加就是第i天需要的教室数量//如果有一天需要的教室比能提供的多,就不行if(s>w[i]) return false;}return true;
}
int main()
{scanf("%d%d",&n,&m);for(int i=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份订单,找到最后一个能处理的订单int l=0,r=m; //从0开始,有可能一个订单都不能满足while(l<r){int mid=l+r+1 >> 1; //取中点,这里+1是模板需要if(check(mid)) l=mid;else r=mid-1;}if(r==m) puts("0");  //所有订单都可以满足else printf("-1\n%d\n",r+1);  //如果不能满足,输出第一个不能满足的编号} 

为什么这里的代码不需要初始化差分数组:

    for(int i=1;i<=mid;i++){b[i]=d[i]-d[i-1];}

因为题目中初始情况下,每一天所需的教室数都为0,所需的教室数量是根据后面的订单才发生变化的,也就是说,要计算教室数量,就可以通过订单(差分数组)来计算,这些得到的差值加起来就是某天所需要的教室数量。

为什么L要从0开始?

    int l=0,r=m; //从0开始,有可能一个订单都不能满足while(l<r){int mid=l+r+1 >> 1; //取中点,这里+1是模板需要if(check(mid)) l=mid;else r=mid-1;}if(r==m) puts("0");  //所有订单都可以满足else printf("-1\n%d\n",r+1);  //如果不能满足,输出第一个不能满足的编号

当n和m都为1,且这一天都不能满足,正确答案应该是-1 1

但若从1开始,则不会进入while循环,直接输出0

若从0开始,则会将r变为0,输出-1 0+1

差分

再看一道经典差分题,也可以用上面的【差分数组是原数组相邻元素的差值】来解:

题目描述

输入一个长度为 n 的整数序列。

接下来输入 m 个操作,每个操作包含三个整数 l,r,c表示将序列中 [l,r] 之间的每个数加上 c。

请你输出进行完所有操作后的序列。

输入格式

第一行包含两个整数 n和 m。

第二行包含 n个整数,表示整数序列。

接下来 m行,每行包含三个整数 l,r,c表示一个操作。

输出格式

共一行,包含 n个整数,表示最终序列。

数据范围

1≤n,m≤100000,
1≤l≤r≤n,
−1000≤c≤1000,
−1000≤整数序列中元素的值≤1000

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

原解法:

#include<iostream>
using namespace std;
int m,n;
typedef long long ll;
const int N=1e5+10;
int a[N];
int diff[N]; int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=n;i++){diff[i]=a[i]-a[i-1];  //差分初始化}while(m--){int c,l,r;cin>>l>>r>>c;diff[l]+=c;diff[r+1]-=c;		 //这里是自增自减,记得+=,-=		}for(int i=1;i<=n;i++){a[i]=diff[i]+a[i-1];} //记得最后还原成原数组,这样才能作用到原数组上面for(int i=1;i<=n;i++){cout<<a[i]<<" ";}return 0;	
}

新解法:

#include<iostream>
#include<cstring>
using namespace std;
int m,n;
typedef long long ll;
const int N=1e5+10;
int a[N];
int diff[N]; int main()
{ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>a[i];}for(int i=1;i<=n;i++){diff[i]=a[i]-a[i-1];  //差分初始化,因为这个本身就有给整数序列,所以需要计算,而借教室那道题,本身所需教室为0,是通过一个一个订单计算得到的,所以不需要计算初始值}while(m--){int c,l,r;cin>>l>>r>>c;diff[l]+=c;diff[r+1]-=c;		 //这里是自增自减,记得+=,-=		}int s=0;for(int i=1;i<=n;i++){//不同之处:这次我们直接通过差值来计算s+=diff[i];cout<<s<<" ";} return 0;	
}

这道题和借教室的不同就在于:差分初始化,因为这个题目本身就有给整数序列(即原来的a是有初始值的),所以需要计算差分数组的初始值,而借教室那道题,本身所需教室为0,是通过一个一个订单计算得到的,所以不需要计算初始值

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

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

相关文章

MySQL 锁机制

优质博文&#xff1a;IT-BLOG-CN 定义&#xff1a;锁是计算机协调多个进程或线程并发访问某一资源的机制。 一、表锁&#xff08;偏读&#xff09; MyISAM 引擎&#xff0c;开销小&#xff0c;加锁快&#xff0c;无死锁、锁定粒度大、发生锁冲突的粒度最高&#xff0c;并发度…

【MySQL】对表的相关操作(DDL)

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前学习计网、mysql和算法 ✈️专栏&#xff1a;MySQL学习 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章对你有帮助的话 欢迎 评论&#x1f4ac…

GPT-5可能会在今年夏天作为对ChatGPT的“实质性改进”而到来

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

MQ组件之RabbitMQ学习

MQ组件之RabbitMQ入门 同步调用和异步调用 在微服务架构中&#xff0c;服务之间的调用有同步调用和异步调用两种方式。 我们使用OpenFeign去调用是同步调用&#xff0c;同步调用的缺点很明显&#xff0c;在下图的场景中&#xff0c;支付完成后需要调用订单服务、仓库服务、短…

字符型数据详解

1 字符常量 C的字符常量是用单撇号括起来的一个字符。如a,x,D,?,$等都是字符常量。注意,a和A是不同的字符常量。 除了以上形式的字符常量外,C还允许用一种特殊形式的字符常量&#xff0c;就是以一个“\”开头的字符序列。例如,前面已经遇到过的&#xff0c;在printf函数中的…

DPDK and Trex环境指南

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 目录 前言 一、测试拓扑图 二、VirtualBox的网卡配置 三、DPDK支持的网卡 四、DPDK安装 1.DPDK向导 1). 英文向导 2). 中文向导 2.DPDK源码下载 3.DPDK源码解压 4.…

今日问题:动态分配内存出错

2024.3.22 在搜素了许多文章和查阅了许多博客后依然没有找到问题所在&#xff0c;最后无意之间翻看以前的关于动态内存管理的代码后发现&#xff1a; 没加头文件&#xff1a;#include<stdlib.h> 苦笑不得了属于是 #define _CRT_SECURE_NO_WARNINGS 1 #include<stdio…

蓝桥杯day7刷题日记

P8697 [蓝桥杯 2019 国 C] 最长子序列 思路&#xff1a;直接遍历&#xff0c;和子序列相同就记录&#xff0c;不然就下一位 #include <iostream> #include <string> using namespace std; int res;int main() {string s,t;cin>>s>>t;int i0,j0;while…

关于msvcp140.dll丢失的解决方法详情介绍,修复dll文件的安全注意事项

在使用电脑的过程中&#xff0c;是否有遇到过关于msvcp140.dll丢失的问题&#xff0c;遇到这样的问题你是怎么解决的&#xff0c;都有哪些msvcp140.dll丢失的解决方法是能够完美解决msvcp140.dll丢失问题的&#xff0c;今天小编将带大家去了解msvcp140.dll文件以及分析完美解决…

代码随想录 Day-23

力扣题目 406.根据身高重建队列 思路 这里可以看出来是有两个维度考虑&#xff0c;和力扣题目 135.分发糖果&#xff08;可以看我day-22的文章&#xff09; 有点类似。 因此遇到这种两个维度权衡的时候&#xff0c;一定是先考虑一个维度再按照另一个维度来重新考虑排序。 两…

innodb 的 buffer pool 管理 page

page 页结构 page是整个InnoDB存储的最基本构件&#xff0c;也是InnoDB磁盘管理的最小单位&#xff0c;与数据库相关的所有内容都存储在这种Page结构里。 Page分为几种类型&#xff0c;常见的页类型有 数据页(Btree Node)Undo页(Undo Log Page)系统页(System Page)事务数据页 …

PC显示字体和浏览器的字体不一致

1&#xff1a;设置了PC的区域&#xff0c;显示字符&#xff0c; 2&#xff1a;导致浏览器显示的字符一半大一半小 3&#xff1a;为什么去设置这个&#xff0c;因为担心封号 4&#xff1a;不让它检测出我是他大佬

【C++初阶】第七站:string类的初识(万字详解、细节拉满)

前言&#xff1a; &#x1f4cd;本文知识点&#xff1a;string的初识 &#x1f4a8;个人博客:Dream_Chaser&#xff5e;-CSDN博客 &#x1f6a9;本专栏&#xff1a;C 目录 一、什么是STL 二、STL的六大组件 三、STL的缺陷 四、为什么学习string类&#xff1f; 五、标准库中…

云ERP vs 本地ERP:优劣对比与选择指南

在性能方面&#xff0c;本地ERP需要需要较高级别的计算机系统和其他设备来确保其高效运行。如果企业的计算机设备不够先进&#xff0c;那么选择本地ERP可能导致系统性能下降。而云ERP解决方案则能保证性能&#xff0c;只要企业拥有稳定的互联网连接即可。 在成本方面&#xff0…

Linux的基本使用

1.Linux的背景 1.1什么Linux Linux是⼀个操作系统.和Windows是"并列"的关系. 1.2Linux系统的优势 1. 开源(意味着免费,便宜) 2. 稳定(Linux可以运⾏很多年,都不会发⽣重⼤问题) 3. 安全(Linux只有管理员或者特定⽤⼾才能访问Linux内核) 4. ⾃由(不会被强加商业产品和…

EasyCloud软件简介

运行环境&#xff1a;Win10 PCL1.9 VTK8.1 Qt5.12 VS2017 基于PCL点云库的三维点云数据处理软件 1&#xff0e;软件用户界面 本软件的用户界面主要包括以下几个部分&#xff08;如图1&#xff09;&#xff1a; [1]菜单栏&#xff0c;将软件功能模块划分为不同菜单&…

JAVA八股--集合面试题

AVA八股--集合面试题--上 java只有值传递&#xff0c;没有引用传递代理模式Java之HashMap和Hashtable选用 ArrayDeque 来实现队列要比 LinkedList 更好为什么HashMap的长度一定是2的次幂&#xff1f;HashMap常见遍历方式 java只有值传递&#xff0c;没有引用传递 文章讲解 文…

第四讲 Buffer Pool

问题&#xff1a;DBMS 是如何管理其内存和磁盘之间来回移动数据的&#xff1f; 答案&#xff1a;在决定如何在磁盘中来回移动数据时&#xff0c;我们必须考虑两个关键方面&#xff1a; 空间控制【Spatial Control】&#xff1a; 将页【pages】写在在磁盘的什么地方&#xff…

vsc ctrl+. 无效的问题

描述 ubuntu ibus 输入法 vsc ctrl.快捷键无效 输出 _e 解决方案: 运行 ibus-setup 把表情符号这里的快捷键改了

mysql 空间查询 多边形内的点

数据库查询 # 1新增空间point类型坐标字段 ALTER TABLE gaoxin_isdp.business_master ADD COLUMN location2 point NULL AFTER location;# 2从原字段更新点位字段&#xff0c;原字段poi1是字符串106.474596,29.464360 UPDATE business_master SET location POINT(substr(poi…