• [NOIP2012提高组]借教室


    题目:洛谷P1083、Vijos P1782、codevs1217。

    题目大意:有n天,每天可以借a[i]个教室。有m个请求,每个请求要在一段连续天数内借固定数目的教室。请求只能按顺序批准。求第一个无法批准的请求是第几个请求,或全部可以批准。

    解题思路:看到区间,容易想到线段树维护(正解貌似是二分,燃鹅我只能理解线段树啊~)。这里显然只需维护最小值。不过如果姿势不好,可是会T的哟。

    线段树肯定很好想,但想不超时,就得优化。例如读入优化、标记永久化、递归过程能用全局变量用全局变量、搜到答案直接退出等。最后提交,坐等AC即可。

    C++ Code:

    #include<cstdio>
    #include<cstdlib>
    #include<cctype>
    using namespace std;
    long long d[4000005],p[4000005];
    int i,n,m,L,R,k;
    inline long long min(long long a,long long b){return(a<b)?a:b;}
    inline int readint(){
    	char c=getchar();
    	int p=0;
    	for(;!isdigit(c);c=getchar());
    	for(;isdigit(c);c=getchar())p=(p<<3)+(p<<1)+(c^'0');
    	return p;
    }
    void make_tree(int l,int r,int o){
    	p[o]=0;
    	if(l==r){
    		d[o]=readint();
    		return;
    	}
    	int mid=l+r>>1,lf=o<<1,rg=o<<1|1;
    	make_tree(l,mid,lf);
    	make_tree(mid+1,r,rg);
    	d[o]=min(d[lf],d[rg]);
    }
    void change(int l,int r,int o){
    	if(L<=l&&r<=R){
    		p[o]+=k;
    		if(d[o]-p[o]<0){
    			printf("-1
    %d
    ",i);
    			exit(0);
    		}
    		return;
    	}
    	int mid=l+r>>1,lf=o<<1,rg=o<<1|1;
    	if(L<=mid)change(l,mid,lf);
    	if(mid<R)change(mid+1,r,rg);
    	d[o]=min(d[lf]-p[lf],d[rg]-p[rg]);
    	if(d[o]-p[o]<0){
    		printf("-1
    %d
    ",i);
    		exit(0);
    	}
    }
    int main(){
    	n=readint(),m=readint();
    	make_tree(1,n,1);
    	for(i=1;i<=m;++i){
    		k=readint(),L=readint(),R=readint();
    		change(1,n,1);
    	}
    	puts("0");
    	return 0;
    }
    

    --------------------------------------------------------2017-10-11--------------------------------------------------------

    偶然想到这道题,突然就想到了二分的方法。

    可以发现,当订单无法满足时,小于答案的所有订单都可以满足,而大于等于答案的都不能满足。

    利用这个特性,我们就可以进行二分。

    重点是如何验证答案呢?

    可以发现知道了答案就相当于区间求和问题,差分一遍,然后对于每一天判断借的教室数量有没有超出限制就可以了。

    时间复杂度和线段树是一样的,但线段树常数特别大,如果出一个很大的且能满足所有订单的数据,就不能中途退出,就可能被卡掉。

    C++ Code:

    #include<cstdio>
    #include<cctype>
    #include<cstring>
    using namespace std;
    #define ll long long
    ll p[1000005],s[1000005];
    int n,m;
    struct Dd{
    	int num,b,e;
    }q[1000005];
    template<typename T>
    inline void read(T& p){
    	char c=getchar();
    	for(;!isdigit(c);c=getchar());
    	for(p=0;isdigit(c);c=getchar())p=(p<<3)+(p<<1)+(c^'0');
    }
    bool ok(int ans){
    	memset(s,0,sizeof s);
    	for(int i=1;i<=ans;++i)
    	s[q[i].b]+=q[i].num,s[q[i].e+1]-=q[i].num;
    	ll now=0;
    	for(int i=1;i<=n;++i)
    	if((now+=s[i])>p[i])return false;
    	return true;
    }
    int main(){
    	read(n);
    	read(m);
    	for(int i=1;i<=n;++i)read(p[i]);
    	for(int i=1;i<=m;++i)
    	read(q[i].num),read(q[i].b),read(q[i].e);
    	int l=0,r=m,ans=0;
    	while(l<=r){
    		int mid=(l+r)>>1;
    		if(ok(mid))l=(ans=mid)+1;else
    		r=mid-1;
    	}
    	if(ans==m)puts("0");else
    	printf("-1
    %d
    ",ans+1);
    	return 0;
    }
    
  • 相关阅读:
    VS2010、SQL Server 2008和SQL Server 2012安装详解
    IIS服务寄宿
    C#中错误:不包含适合于入 口点的静态“Main”方法 的解决方法
    硬件的一些性能指标
    SATA SAS SSD 硬盘介绍和评测
    mysql数据库锁定机制
    mysql日志设置优化
    MySQL硬件瓶颈分析
    可扩展性设计之数据切分
    硬件环境对系统性能的影响
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/7528332.html
Copyright © 2020-2023  润新知