NOIp2012借教室题解

原题见(https://www.luogu.org/problem/show?pid=1083
这道题我第一眼看见果断是线段树啊,但是NOIP第二天第二题考线段树岂不是药丸,但是好来才知道正解居然是二分答案,如果是考场上根本想不到啊,二分的话首先要满足单调的,我们知道订单的顺序肯定是单调的,这样子把订单二分就行了,更简单一点的就是NOIp2015的跳石头,如果还有没有思路的可以去看看这个~飞机票(http://blog.csdn.net/a1351937368/article/details/76473342)其实说到这里就应该有点思路了吧(贴下代码,基本上重要的注释都在里面写出来了):

//二分 
#include<cstdio>
#include<queue>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<stack>
#include<cmath>
using namespace std;

long long n,m,room[1001010],f[1010010],r[1001010];
struct node{
    int num,s,e;
}a[1001000];//num表示第i个订单需要教室个数,
//s(tart)为开始的日子,e(nd)为结束的日子 

inline int read(){
    int num;
    char ch;
    while((ch=getchar())<'0' || ch>'9');
    num=ch-'0';
    while((ch=getchar())>='0' && ch<='9'){
        num=num*10+ch-'0';
    }
    return num;
}
inline void out(int x){
    if(x>=10){
        out(x/10);
    }
    putchar(x%10+'0');
}
inline bool deal(int mid){
    //判断到第mid个订单是否会出现教室不够借的现象 
    memset(f,0,sizeof(f)),memset(r,0,sizeof(r));//初始化数组 
    for(register int i=1;i<=mid;i++){//一到mid的订单逐个枚举 
        f[a[i].s]-=a[i].num,f[a[i].e+1]+=a[i].num;//当前开始的减去当前订单需要的,结束的加上需要的 
        //用前缀和修改区间值 
    }
    for(register int i=1;i<=n;i++){
        f[i]+=f[i-1];//一维前缀和 
        if(room[i]+f[i]<0){//room[i]为第i天的教室个数,如果第i天需要的教室数加上拥有的教室数小于0 
            return true;//当前节点会出现教室不够用的情况 
        }
    }
    return false;//当前节点不会出现教室不够用的情况 
} 

int main(){
    n=read(),m=read();//天数和订单数量 
    for(register int i=1;i<=n;i++){
        room[i]=read();//第i天可用于租借的教室数量 
    }
    for(register int i=1;i<=m;i++){
        a[i].num=read(),a[i].s=read(),a[i].e=read();//租借数量,租借开始时间,租借结束时间 
    }
    int l=1,r=m,mid;//二分开始 
    while(l<r){
        mid=(l+r)/2;
        if(deal(mid)){//如果mid不满足
            r=mid;//如果当前的mid值不符合那么将右节点左移 
        }
        else{
            l=mid+1;//否则左节点右移 
        }
    }
    if(r==m){//说明没有出现教室不够用的情况 
        out(0);
    }
    else{
        printf("-1 \n"),out(r);
    }
    return 0;
}

再加点玄学优化这道题可以说跑的很快20个点2256ms就可以跑完了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值