NOIp2012借教室题解

来源:互联网 发布:个体网络销售营业执照 编辑:程序博客网 时间:2024/05/16 09:56

原题见(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就可以跑完了

原创粉丝点击