借教室与差分

原题

题目描述

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

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

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

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

我们需要处理接下来 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.mfbz.cn/a/476028.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

9.测试教程-性能测试概述

文章目录 1.常见的性能问题2.为什么要进行性能测试3.性能测试实施的流程4.概念和术语介绍5.性能测试模型6.性能测试方法介绍7.性能测试实施与管理8.性能测试前期准备9.测试工具引入10.性能测试方案11.性能测试设计与开发12.性能测试设计与管理13.性能测试设计与调优14.性能测试…

Python+Appium实现自动化测试的使用步骤

一、环境准备 1.脚本语言&#xff1a;Python3.x IDE&#xff1a;安装Pycharm 2.安装Java JDK 、Android SDK 3.adb环境&#xff0c;path添加E:\Software\Android_SDK\platform-tools 4.安装Appium for windows&#xff0c;官网地址Redirecting 点击下载按钮会到GitHub的下载…

广西开放大学电大搜题微信公众号,助你快速解题,轻松学习!

近年来&#xff0c;广西开放大学电大搜题微信公众号备受关注。作为一名电大学者&#xff0c;我有幸亲身体验了该公众号的功能&#xff0c;并深感其对广大学生学习的帮助之大。 广西开放大学作为一所具有百年历史的学府&#xff0c;一直致力于为学生提供优质的教育资源。而电大…

Uibot6.0 (RPA财务机器人师资培训第2天 )采购付款——网银付款机器人案例实战

训练网站&#xff1a;泓江科技 (lessonplan.cn)https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981https://laiye.lessonplan.cn/list/ec0f5080-e1de-11ee-a1d8-3f479df4d981(本博客中会有部分课程ppt截屏,如有侵权请及请及时与小北我取得联系~&#xff0…

【Python + Django】启动简单的文本页面

前言&#xff1a; 为了应付&#xff08;bushi&#xff09;毕业论文&#xff0c;总要自己亲手搞一个像模像样的项目出来吧 ~ ~ 希望自己能在新的连载中学到项目搭建的知识&#xff0c;这也算是为自己的测试经历增添光彩吧&#xff01;&#xff01;&#xff01; 希望、希望大家…

09 事务和连接池

文章目录 properties文件连接池service层实现类dao层实现类dao层实现类 连接池类: 创建线程池静态常量&#xff0c;用于放连接。 创建Properties静态常量&#xff0c;用于解析properties文件 静态代码块中&#xff0c;解析properties文件&#xff0c;将解析结果用于创建连接池 …

Linux快速入门,上手开发 02.VMware的安装部署

倘若穷途末路&#xff0c;那便势如破竹 —— 24.3.21 一、VMware的作用 在Windows或IOS系统下&#xff0c;给本地电脑安装VMware虚拟机&#xff0c;用来在虚拟机上安装Linux系统&#xff0c;避免重复资源的浪费&#xff0c;可以在虚拟机上搭建Linux系统进行学习 二、VMware的安…

PCL点云处理之中值计算(二百三十三)

PCL点云处理之中值计算(二百三十三) 一、算法介绍二、算法实现1.代码2.结果一、算法介绍 读取的点云是无序散乱的,点云坐标包括xyz三个维度,以常用的z高程维度为例,计算其高程中值,获取对应的点。 主要涉及到根据高程对点云进行排序的操作,下面是具体的代码和结果。 …

视频号下载助手失效了?如何解决下载视频问题!

在刷短视频的时候难免会遇到部分的视频号视频下载不下来&#xff0c;那我们该如何解决视频号下载问题呢&#xff1f; 视频号下载助手解决方案 视频号下载助手失效分为两种情况! 1、可以解析&#xff0c;但不能下载 根据使用视频号下载助手常见的问题&#xff0c;我们发现会有…

C++进阶--哈希

哈希概念 哈希&#xff08;Hash&#xff09;是一种常见的密码学技术和数据结构&#xff0c;它将任意长度的输入通过散列算法转换成固定长度的输出&#xff0c;这个输出被称为散列值或哈希值。哈希函数是一种单向函数&#xff0c;即从哈希值无法反推出原始输入值。 哈希函数具有…

AJAX 前端开发利器:实现网页动态更新的核心技术

AJAX AJAX是开发者的梦想&#xff0c;因为你可以&#xff1a; 在不重新加载页面的情况下更新网页在页面加载后请求来自服务器的数据在页面加载后接收来自服务器的数据在后台向服务器发送数据 HTML页面 <!DOCTYPE html> <html> <body><div id"dem…

你要的个性化生信分析服务今天正式开启啦!定制你的专属解决方案!全程1v1答疑!

之前在 干货满满 | 给生信小白的入门小建议 | 掏心掏肺版 中有提到&#xff0c;如果小伙伴们真的想学好生信&#xff0c;那编程能力是必须要有的&#xff01;但是可能有些小伙伴们并没有那么多的时间从头开始学习编程&#xff0c;又或是希望有人指导或者协助完成生信分析工作&a…

Qt学习--界面知识点大杂烩

在开发过程中&#xff0c;通常需要打开或者保存上位机数据到本地&#xff0c;这时候就需要用到

数据结构面试常见问题之Insert or Merge

&#x1f600;前言 本文将讨论如何区分插入排序和归并排序两种排序算法。我们将通过判断序列的有序性来确定使用哪种算法进行排序。具体而言&#xff0c;我们将介绍判断插入排序和归并排序的方法&#xff0c;并讨论最小和最大的能区分两种算法的序列长度。 &#x1f3e0;个人主…

打流仪/网络测试仪这个市场还能怎么卷?

#喝了点&#xff0c;码点字# 以下为个人观点&#xff0c;看看就好&#xff0c;如有冒犯&#xff0c;私信删稿 都有哪些厂商在做打流仪/网络测试仪 -洋品牌&#xff1a;思博伦/Viavi-Spirent&#xff0c;是德/Keysight-Ixia&#xff0c;信雅纳/Lecroy-Xena&#xff0c; -国产…

Ubuntu20.04 安装fcitx5输入法

序 ubuntu 20.04.3下fcitx5 需要从flatpak安装&#xff0c;&#xff08;由于qt版本&#xff0c;fcitx5-config只能安装在20.10上&#xff09;&#xff0c;中间出了各种问题&#xff0c;最后发现以下解决方案最好&#xff1a; 安装flatpak (建议使用官方ppa,版本较新) 1 2 3 …

k8s系列之十五 Istio 部署Bookinfo 应用

Bookinfo 应用中的几个微服务是由不同的语言编写的。 这些服务对 Istio 并无依赖&#xff0c;但是构成了一个有代表性的服务网格的例子&#xff1a;它由多个服务、多个语言构成&#xff0c;并且 reviews 服务具有多个版本。 该应用由四个单独的微服务构成。 这个应用模仿在线书…

std::shared_ptr与std::make_unique在类函数中的使用

在最近学习cartographer算法的时候&#xff0c;发现源码中大量的使用了std::shared_ptr与std::make_unique&#xff0c;对于这些东西之前不是很了解&#xff0c;为了更好的理解源代码&#xff0c;因此简单学习了一下这块内容的使用&#xff0c;在这里简单记个笔记。 std::shar…

嵌入式软件面试-linux-中高级问题

Linux系统启动过程&#xff1a; BIOS自检并加载引导程序。引导程序&#xff08;如GRUB&#xff09;加载Linux内核到内存。内核初始化硬件&#xff0c;加载驱动&#xff0c;建立内存管理。加载init进程&#xff08;PID为1&#xff09;&#xff0c;通常是systemd或SysVinit。init…

安达发|印刷包装APS生产计划排产系统的商业价值

在当今快速消费和竞争激烈的市场环境中&#xff0c;印刷包装行业面临着前所未有的挑战。随着客户需求的多样化、交付期限的缩短以及原材料价格的波动&#xff0c;传统的生产管理方法已无法满足现代印刷包装企业的复杂需求。为了保持竞争力&#xff0c;企业必须采用先进的生产计…