[题解]P1083 [NOIP2012 提高组] 借教室

解法\(1\):线段树 - \(O((n+m)\log n)\)

比较直观的一种做法,但是可能需要卡一下输入(这里没卡也过了,但要注意输入是\(10^6\)级的,为了保险一定要加)。

#include<bits/stdc++.h>
#define lc (x<<1)
#define rc ((x<<1)|1)
#define int long long
using namespace std;
int n,m,a[1000010],minn[4000010],tag[4000010];
void update(int x){
minn[x]=min(minn[lc],minn[rc]);
}
void ch(int x,int v){
tag[x]+=v;
minn[x]+=v;
}
void pushdown(int x){
if(tag[x]){
ch(lc,tag[x]);
ch(rc,tag[x]);
tag[x]=0;
}
}
void build(int l,int r,int x){
if(l==r){
minn[x]=a[l];
return;
}
int mid=(l+r)>>1;
build(l,mid,lc);
build(mid+1,r,rc);
update(x);
}
void modify(int a,int b,int v,int l,int r,int x){
pushdown(x);
if(a<=l&&r<=b){
ch(x,v);
return;
}
int mid=(l+r)>>1;
if(a<=mid) modify(a,b,v,l,mid,lc);
if(b>mid) modify(a,b,v,mid+1,r,rc);
update(x);
}
int query(int a,int b,int l,int r,int x){
pushdown(x);
if(a<=l&&r<=b) return minn[x];
int mid=(l+r)>>1,ans=LLONG_MAX;
if(a<=mid) ans=min(ans,query(a,b,l,mid,lc));
if(b>mid) ans=min(ans,query(a,b,mid+1,r,rc));
return ans;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
}
build(1,n,1);
for(int i=1;i<=m;i++){
int v,l,r;
cin>>v>>l>>r;
modify(l,r,-v,1,n,1);
if(query(1,n,1,n,1)<0){
cout<<"-1\n"<<i<<"\n";
return 0;
}
}
cout<<"0\n";
return 0;
}

解法\(2\):二分答案 - \(O((n+m)\log m)\)

二分枚举申请的编号,对于枚举出的编号。通过差分,计算出处理完当前编号后,每一天剩余的教室数量。如果最终结果存在负数,则r=mid,否则l=mid+1。因为我们要找的是使存在负数的最小编号。

#include<bits/stdc++.h>
#define int long long
#define N 1000010
#define M 1000010
using namespace std;
int n,m,a[N],b[N],tb[N],c[M],ld[M],rd[M];
bool check(int d){
for(int i=1;i<=n;i++) tb[i]=b[i];
for(int i=1;i<=d;i++) tb[ld[i]]-=c[i],tb[rd[i]+1]+=c[i];
for(int i=1;i<=n;i++) tb[i]+=tb[i-1];
for(int i=1;i<=n;i++) if(tb[i]<0) return 1;
return 0;
}
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
b[i]=a[i]-a[i-1];
}
for(int i=1;i<=m;i++) cin>>c[i]>>ld[i]>>rd[i];
int l=1,r=m;
bool flag=0;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)){//不合法
flag=1;
r=mid;
}else{
l=mid+1;
}
}
if(!flag) cout<<"0\n";
else cout<<"-1\n"<<l<<"\n";
return 0;
}

解法\(3\) - \(O(n+m)\)

总体思路就是用一个指针\(j\),初始为\(m\)。对于每一天,判断完成操作\(1\sim j\)后是否仍然合法。如果不合法了,就把\(j\)往前挪,同时撤回操作,直到该天合法为止。

最后,如果\(j=m\),则说明所有操作都是合法的,输出0

否则,我们需要输出导致不合法的第一个操作。而\(j\)表示的是合法的最后一个操作,输出\(j+1\)即可。

此算法的优势在于,枚举的每一天不需要从最后开始移动指针,而是从上一天的位置开始移动,大大减少了冗余操作。

注意到\(j\)是只减不增的,所以while循环一共最多执行\(m\)次。而for一共执行\(n\)次,所以复杂度是\(O(n+m)\)。

#include<bits/stdc++.h>
#define N 1000010
#define M 1000010
#define int long long
using namespace std;
int n,m,a[N],c[M],l[M],r[M];
int cf[N];
signed main(){
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>a[i];
for(int i=1;i<=m;i++){
cin>>c[i]>>l[i]>>r[i];
cf[l[i]]+=c[i],cf[r[i]+1]-=c[i];
}
int j=m,sum=0;
//sum表示完成操作1~j后,第i天一共用去多少教室
for(int i=1;i<=n;i++){
sum+=cf[i];//cf[i]表示完成操作j之后,第i天一共用去多少个教室
while(sum>a[i]){//用去的>已有的,不合法,需要撤回操作
cf[l[j]]-=c[j],cf[r[j]+1]+=c[j];
if(l[j]<=i&&i<=r[j]) sum-=c[j];
j--;
}
}
if(j==m) cout<<"0\n";
else cout<<"-1\n"<<j+1<<"\n";
return 0;
}

[题解]P1083 [NOIP2012 提高组] 借教室的更多相关文章

  1. 【分块】【常数优化】【Orz faebdc】洛谷 P1083 NOIP2012提高组 借教室

    分块90分. By AutSky_JadeK [重点在下面] #include<cstdio> #include<cmath> using namespace std; #de ...

  2. [NOIp2012提高组]借教室

    OJ题号:洛谷1083 思路:ZKW线段树 #include<cstdio> #include<cctype> #include<algorithm> inline ...

  3. 洛谷P1083 [NOIP2012提高组Day2T2]借教室

    P1083 借教室 题目描述 在大学期间,经常需要租借教室.大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室.教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样. 面对海量租借 ...

  4. 题解 P1850 [NOIP2016 提高组] 换教室

    做完这道题才略微感觉自己懂了一点关于概率与期望的知识QAQ... 一:关于概率与期望的定义 转载节选于blog 1.什么是数学期望? 数学期望亦称期望.期望值等.在概率论和统计学中,一个离散型随机变量 ...

  5. 刷题总结——疫情控制(NOIP2012提高组)

    题目: 题目背景 NOIP2012 提高组 DAY2 试题. 题目描述 H 国有 n 个城市,这 n 个城市用 n-1 条双向道路相互连通构成一棵树,1 号城市是首都,也是树中的根节点. H 国的首都 ...

  6. 【题解】NOIP2016提高组 复赛

    [题解]NOIP2016提高组 复赛 传送门: 玩具谜题 \(\text{[P1563]}\) 天天爱跑步 \(\text{[P1600]}\) 换教室 \(\text{[P1850]}\) 组合数问 ...

  7. 【题解】NOIP2016 提高组 简要题解

    [题解]NOIP2016 提高组 简要题解 玩具迷题(送分) 用异或实现 //@winlere #include<iostream> #include<cstdio> #inc ...

  8. GZOJ 1361. 国王游戏【NOIP2012提高组DAY1】

    国王游戏[NOIP2012提高组DAY1] Time Limit:1000MS Memory Limit:128000K Description 国王游戏(game.cpp/c/pas) [问题描述] ...

  9. 【题解】NOIP2015提高组 复赛

    [题解]NOIP2015提高组 复赛 传送门: 神奇的幻方 \([P2615]\) 信息传递 \([P2661]\) 斗地主 \([P2668]\) 跳石头 \([P2678]\) 子串 \([P26 ...

  10. 【题解】NOIP2017 提高组 简要题解

    [题解]NOIP2017 提高组 简要题解 小凯的疑惑(数论) 不讲 时间复杂度 大力模拟 奶酪 并查集模板题 宝藏 最优解一定存在一种构造方法是按照深度一步步生成所有的联通性. 枚举一个根,随后设\ ...

随机推荐

  1. CentOS7 vsftpd服务搭建与详解

    FTP介绍 文件传输协议(File Transfer Protocol,FTP),基于该协议FTP客户端与服务端可以实现共享文件.上传文件.下载文件. FTP 基于TCP协议生成一个虚拟的连接,主要用 ...

  2. Flask之model以及缓存

    Flask默认并没有提供任何数据库操作的API. Flask中可以自己的选择数据,用原生语句实现功能,也可以选择ORM(SQLAlchemy,MongoEngine)原生SQL缺点 代码利用率低,条件 ...

  3. Java 内存模型与 Happens-Before 关系深度解析

    在 Java 并发编程中,Java 内存模型(Java Memory Model, JMM)与 Happens-Before 关系是理解多线程数据可见性和有序性的核心理论.本文从 JMM 的抽象模型出 ...

  4. 长亭雷池WAF(safeline)社区版安装教程

    雷池WAF的技术文档,并不包含 Docker 和 Docker Compose V2 安装文档,更新记录一下,共同学习,共同进步 配置需求 操作系统:Linux 指令架构:x86_64 软件依赖:Do ...

  5. FastAPI权限配置:你的系统真的安全吗?

    url: /posts/96b6ede65030daa4613ab92da1d739a6/ title: FastAPI权限配置:你的系统真的安全吗? date: 2025-06-26T07:35:3 ...

  6. Swag - 将Go注释转换为Swagger文档的强大工具

    项目标题与描述 Swag是一个强大的Go语言工具,能够将代码中的注释自动转换为符合Swagger 2.0规范的API文档.项目支持多种主流Go Web框架,包括Gin.Echo等,通过简单的代码注释即 ...

  7. 花了不少时间,修复了一个SharpIco生成图标的bug

    前言 上个月我用 dotnet9 AOT 开发了一个 ico 图标生成工具 SharpIco 这个实用小工具一经发布就受到不少朋友的关注 最近还被做成了网站,有图形化界面来一键生成 ico 图标,更方 ...

  8. 微信小店与微信小程序简单集成指南

    微信小店现已全面打通小程序生态,为开发者提供强大的电商能力支持.本文将详细介绍各项集成功能及代码实现方案. 一.商品展示与交易能力 1. 商品卡片嵌入 // 基础商品卡片嵌入 <store-pr ...

  9. JS循环遍历对象,获取key:value

    https://blog.csdn.net/lyn1772671980/article/details/79093459 let obj = {        'a':'aa',        'b' ...

  10. 自定义Excel右下角状态栏的显示项

    Excel右下角的状态栏是一个非常方便和有用的显示栏,在执行一些简单的计算时可以直接选取需要计算的区域即可得到汇总,计数,平均值等结果. 如果需要调整状态栏的显示选项,则在状态栏处右键点击: 可以选中 ...