[NOIp2012] luogu P1083 借教室

该*的英语,这么长还要背。

题目描述

你有 n n n 个数 a i {a_i} ai m m m 次操作,每次操作将 [ l , r ] [l,r] [l,r] 区间的每个数减去 c c c。要求任何时刻 ∀ x ∈ [ 1 , n ] \forall x\in[1,n] x[1,n] 都有 a i ≥ 0 a_i\geq0 ai0,请你告诉我最多可以合法地执行多少次操作。

Solution

很明显这是个差分数组对吧。

二分答案即可,每次线性地判断该状态是否合法。时间复杂度 O ( n log ⁡ m ) O(n\log m) O(nlogm)

#include
#include
#include

const int MAXN=1000010;

int n,m;
int d[MAXN],D[MAXN];
int sx[MAXN],sy[MAXN],sd[MAXN];

int check(int x){
	for(int i=1;i<=n;++i)
		d[i]=D[i];
	for(int i=1;i<=x;++i){
		d[sx[i]]-=sd[i];
		d[sy[i]+1]+=sd[i];
	}
//	printf("%d\t",x);
//	for(int i=1;i<=n;++i)
//		printf("%d ",d[i]);
//	puts("");
	int tmp=0;
	for(int i=1;i<=n;++i){
		tmp+=d[i];
		if(tmp<0) return 0;
	}
	return 1;
}
inline int read(){
	int x=0; char c;
	do c=getchar(); while(c<'0'||c>'9');
	while(c>='0'&&c<='9')
		x=x*10+c-48,c=getchar();
	return x;
}
int main(){
	n=read();m=read();d[0]=0;
	for(int i=1;i<=n;++i){
		d[i]=read();
		D[i]=d[i]-d[i-1];
	}
	for(int i=1;i<=m;++i){
		sd[i]=read();
		sx[i]=read();
		sy[i]=read();
	}
	int l=0,r=n,mid,ans=-1;
	while(l<=r){
		mid=(l+r)/2;
		if(check(mid)){
			ans=mid;
			l=mid+1;
		}
		else
			r=mid-1;
	}
	puts(ans==n?"0":"-1");
	if(ans!=n) printf("%d",ans+1);
}

你可能感兴趣的:(信息学,二分)