借教室与差分

原题

题目描述

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

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

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

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

我们需要处理接下来 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.hqwc.cn/news/557304.html

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

相关文章

Python程序设计 基本数据类型及操作

1.计算一元二次方程的根 编写一个计算一元二次方程的根的小程序。 一元二次方程经过整理都可化成一般形式axbxc0&#xff08;a≠0&#xff09;。 其中ax叫作二次项&#xff0c;a是二次项系数&#xff1b;bx叫作一次项&#xff0c;b是一次项系数&#xff1b;c叫作常数项 。 由一…

Android Launcher开发注意事项

在开发Android Launcher时&#xff0c;需要关注性能、用户体验、权限管理、兼容性等方面&#xff0c;同时遵循相关的开发者政策和最佳实践。有几个重要的注意事项&#xff0c;希望对大家有所帮助。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎…

【精彩回顾】百度智能云千帆产品3月21日发布会

3月21日&#xff0c;AI Cloud Day&#xff1a;百度智能云千帆产品发布会在北京举办。会议聚焦百度智能云千帆大模型平台最新进展&#xff0c;分享思考与实践。百度智能云在发布会期间宣布&#xff1a; >>满足企业“效价比”核心诉求&#xff0c;千帆ModelBuilder大模型服…

牛客NC196 编辑距离(一)【较难 DFS/DP,动态规划,样本对应模型 Java,Go,PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/6a1483b5be1547b1acd7940f867be0da 思路 编辑距离问题 什么是两个字符串的编辑距离&#xff08;edit distance&#xff09;&#xff1f;给定字符串s1和s2&#xff0c;以及在s1上的如下操作&#xff1a;插入&…

关于安卓调用文件浏览器(一)打开并复制

背景 最近在做一个硬件产品&#xff0c;安卓应用开发。PM抽风&#xff0c;要求从app打开文件浏览器&#xff0c;跳转到指定目录&#xff0c;然后可以实现文件复制粘贴操作。 思考 从应用开发的角度看&#xff0c;从app打开系统文件浏览器并且选择文件&#xff0c;这是很常见…

Revit2020也能玩衍生式设计?

Revit2021新增的一个好玩功能就是衍生式设计&#xff0c;但是Autodesk2021系列的激活目前还比较麻烦&#xff0c;尤其是要装多款2021软件的时候&#xff0c;注册机用起来还挺烦人的&#xff0c;于是&#xff0c;为了省事&#xff0c;我把GenerativeDesignRevit节点包扔到了Dyna…

vue@2.7.16 使用less、less-loader

遇到问题&#xff0c;npm install less-loader7.3.0 --save安装好less-loader后&#xff0c;执行npm run serve 项目运行不起来&#xff0c;排查后发现在安装less-loader后就提示需要安装less&#xff0c;正确的安装应如下&#xff1a; npm install less less-loader7.3.0 --sa…

AI基础知识(4)--贝叶斯分类器

1.什么是贝叶斯判定准则&#xff08;Bayes decision rule&#xff09;&#xff1f;什么是贝叶斯最优分类器&#xff08;Bayes optimal classifier&#xff09;&#xff1f; 贝叶斯判定准则&#xff1a;为最小化总体风险&#xff0c;只需在每个样本上选择那个能使条件风险最小的…

章文嵩等技术大咖共同探讨企业数据治理和降本增效策略运用!

3 月 16 日&#xff0c;AutoMQ 携手 OceanBase 开源社区、KubeBlocks 举行的《LLMs 时代下企业数据管理与降本增效之路》主题 meetup 顺利落幕。活动邀请了 AutoMQ 联合创始人 & CSO、Linux LVS 创始人 章文嵩&#xff0c;AutoMQ 联合创始人 & CTO、Apache RocketMQ 联…

25.删除链表中倒数第N个结点

题意:给你一个链表,删除链表的倒数第 n 个结点,并且返回链表的头结点。 class Solution { public:ListNode* removeNthFromEnd(ListNode* head, int n) {ListNode* dummyHead=new ListNode(0); //定义虚拟头结点ListNode* fast=dummyHead; //定义快指针ListNode* slow=dummy…

为什么大家都在“挺”鸿蒙?

试想某一天&#xff0c;应用软件能够在手机、电视、手表甚至汽车等设备上&#xff0c;实现无缝流转、纵享丝滑。 这不仅是畅想&#xff0c;而是鸿蒙正在布局的“遥遥领先”。 随着HarmonyOS NEXT鸿蒙星河版面向开发者开放申请、鸿蒙原生应用版图的基本成型&#xff0c;这个国…

聚焦两会:数字化再加速,VR全景助力制造业转型

近年来&#xff0c;随着信息技术、人工智能、VR虚拟现实等新兴技术的不断涌现&#xff0c;数字化正日益成为推动当今经济发展的新驱动力。在不久前的两会上&#xff0c;数字化经济和创新技术再度成为热门话题&#xff1a; 国务院总理李强作政府工作报告&#xff1a; 要深入推…