AcWing 503. 借教室(每日一题)

简介: AcWing 503. 借教室(每日一题)

原题链接:503. 借教室 - AcWing题库

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

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


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


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


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


输出格式


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


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


数据范围


1≤n,m≤10^6

0≤ri,dj≤10^9

1≤sj≤tj≤n


输入样例:

4 3
2 5 4 3
2 1 3
3 2 4
4 2 4

输出样例:

-1
2

解题思路:

此题可用差分+二分或者线段树来解,由于博主能力限制这里会由易懂的差分+二分来讲解。这道题第一感觉应该就是差分了吧,修改区间的值,用差分效率更高一点。我们可以把申请人的需要转化成差分数组,利用前缀和还原,判断i个教室是否满足。如果我们只依靠差分是解决不了此题的,只利用差分时间复杂度为O(nm),大约10^12,肯定会超时,那么我们可以考虑把内层循环利用二分优化掉,具体咋优化呢,我们有了一个申请人编号的差分数组,从第一位申请单到最后一个申请单,越在前面的越容易借到教室,说明教室剩余够多,越到后面剩余可借教室会减少,因为会被前面的申请借去,那就说明第一个不满足的编号越往后概率越高,这样是不是感觉像是一个有序的序列,从头到尾,能满足的概率是由大到小的。那么我们利用二分去查到最后一个能满足的订单,+1即为不能满足的订单,上代码。

#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N=1e6+5;
int n,m;
LL r[N],d[N],s[N],t[N],c[N];
bool cheak(int mid){//判断第mid个申请是否可以满足
  memset(c,0,sizeof(c));//每次都会有判断,防止上次的数据影响本次的判断
  for(int i=1;i<=mid;i++){//采用申请人由0到差分数组,所以直接差分操作即可
    c[s[i]]+=d[i];
    c[t[i]+1]-=d[i];
  }
  int ans=0;
  for(int i=1;i<=n;i++){//求前缀和,即还原数组
    c[i]+=c[i-1];
    if(c[i]>r[i]){//如果需要的教室大于所能提供的教室,则返回false
      return false;
    }
  }
  return true;
}
int main(){
  cin>>n>>m;
  for(int i=1;i<=n;i++){
    cin>>r[i];
  }
  for(int i=1;i<=m;i++){
    cin>>d[i]>>s[i]>>t[i];
  }
  int l=0,r=m;
  while(l<r){//实行二分查找最大能满足的申请人编号
    int mid=l+r+1>>1;//向上取整
    if(cheak(mid))l=mid;
    else r=mid-1;
  }
  if(r==m){//如果最大满足的编号等于m,说明所有订单均可满足
    cout<<0<<endl;
  }else{
    cout<<-1<<endl<<r+1<<endl;//前面定义的为能满足的最大编号,r+1即为第一个不能满足的编号
  }
  return 0;
}

我们上面代码二分查的是最后一个能满足的订单,那么我们也可以去查找第一个不能满足的订单,大部分代码未变,在二分上改成查找左区间即可。部分代码如下:

while(l<r){
    int mid=l+r>>1;
    if(cheak(mid))r=mid;
    else l=mid+1;
  }
  if (!cheak(m)) {
    cout<<0<<endl;
  }else{
    cout<<-1<<endl<<r<<endl;
  }

博主能力有限,所能即为所写,若有不清楚的地方,欢迎各位大佬指出,一定会进行解答和修正,感谢观看,点个赞支持一下吧!

相关文章
|
Java Maven 索引
Logback:同时按照日期和大小分割日志(最新日志可以不带日期或数字)
Logback:同时按照日期和大小分割日志(最新日志可以不带日期或数字)
Logback:同时按照日期和大小分割日志(最新日志可以不带日期或数字)
|
C++
C++程序中的类声明与对象定义
C++程序中的类声明与对象定义
235 1
|
存储 分布式计算 算法
基于 Log 的通用增量 Checkpoint
本文将从 Checkpoint 的性能优化历程出发,介绍 ChangelogStateBackend 的基本机制、应用场景和未来规划,同时介绍最新版本在 State 上的一些优化工作。
7792 2
基于 Log 的通用增量 Checkpoint
|
SQL 关系型数据库 MySQL
MySQL设置表自增步长
MySQL设置表自增步长
670 0
|
分布式计算 Hadoop 大数据
Hadoop数据倾斜局部聚合 + 全局聚合
【7月更文挑战第3天】
197 2
|
Kubernetes Java 微服务
要想Pod好--健康检查少不了
本文主要从以下6个方面介绍Pod的健康检查:刚接触K8S的糗事、Pod生命周期、重启策略、健康检查、如何选择探针、实战,最后还会有知识点的总结和排查Pod问题的总结。
|
固态存储 架构师 开发工具
|
编译器 程序员 C语言
【C++ 类型系统】了解C++ 中 标量、复合、标准布局、平凡和聚合类型
【C++ 类型系统】了解C++ 中 标量、复合、标准布局、平凡和聚合类型
641 0
|
存储 弹性计算 资源调度
K8S下一代设备管理机制:DRA
背景Kubernetes从1.8开始引入了Device Plugin机制,用于第三方设备厂商以插件化的方式将设备资源(GPU、RDMA、FPGA、InfiniBand等)接入Kubernetes集群中。用户无需修改Kubernetes代码,只需在集群中以DaemonSet方式部署设备厂商提供的插件,然后在Pod中申明使用该资源的使用量,容器在启动成功后,便可在容器中发现该设备。然而,随着Kuber
4176 2
K8S下一代设备管理机制:DRA
|
安全 算法 编译器
【C++ 基础 ()和{}括号】深入探索 C++ 的变量初始化:括号和大括号的奥秘
【C++ 基础 ()和{}括号】深入探索 C++ 的变量初始化:括号和大括号的奥秘
1089 0

热门文章

最新文章