CF1260D A Game with Traps

http://codeforces.com/problemset/problem/1260/D
首先很明显可以想到二分答案,把能力值数组排个序就好。
考虑怎么check。
设当前二分值为w,即不能直接跨过权值>w的陷阱。
将所有的陷阱按l升序排列。可以发现,如果两个或多个
陷阱重叠,肯定是这个人直接从这几个陷阱最小的l走到
最大的r最优。
证明?这里只给出两个区间重叠的情况。
假设两个区间分别为[a,b],[c,d],a<c<b<d。
想把队伍从a带到d,第一种的总时间为3(d-a);如果是a->c
->a->b->d->c->d,总耗时是3(c-a)+3(d-b)-(c-b)
=3d+2c-2b-3a>3d-3a。
用双指针模拟就好。

#include<bits/stdc++.h>
using namespace std;
#define re register int
#define F(x,y,z) for(re x=y;x<=z;x++)
#define FOR(x,y,z) for(re x=y;x>=z;x--)
#define I inline void
#define IN inline int
typedef long long ll;
I read(int &res){
    re g=1;register char ch=getchar();res=0;
    while(!isdigit(ch)){
        if(ch=='-')g=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        res=(res<<3)+(res<<1)+(ch^48);
        ch=getchar();
    }
    res*=g;
}
int n,m,k,t,p,q,X,Y,sum,lim,a[202000];
inline bool bbb(int x,int y){
	return x>y;
}
struct Barrier{
	int l,r,w;
	friend bool operator < (Barrier x,Barrier y){
		return x.l==y.l?x.r<y.r:x.l<y.l;
	}
}b[202000];
IN ck(int x){
	if(!x)return 1;
	sum=0;
	lim=a[x];
	p=1;
	while(p<=k&&b[p].w<=lim)p++;
	if(p>k)X=sum=0;
	else sum=X=b[p].l-1;
	while(p<=k){
		Y=b[p].r;
		q=p+1;
		while(q<=k&&(b[q].w<=lim||b[q].l<=Y)){
			if(b[q].w>lim)Y=max(Y,b[q].r);
			q++;
		}
		sum+=3*(Y-X);
		X=Y;
		if(q>k)break;
		sum+=(b[q].l-1-X);
		X=b[q].l-1;
		p=q;
	}
	sum+=(m-X);
	//cout<<x<<" "<<sum<<endl;
	if(sum<=t)return 1;
	return 0;
}
IN divided(int x,int y){
	if(x==y)return x;
	re mid=(x+y+1)>>1;
	if(ck(mid))x=mid;
	else y=mid-1;
	return divided(x,y);
}
int main(){
	read(n);read(m);read(k);read(t);m++;
	F(i,1,n){
		read(a[i]);
	}
	sort(a+1,a+1+n,bbb);
	F(i,1,k){
		read(b[i].l);read(b[i].r);read(b[i].w);
	}
	sort(b+1,b+1+k);
	b[k+1].l=0;
	if(m>t){
		cout<<"0";
		return 0;
	}
	cout<<divided(0,n);
    return 0;
}
posted @ 2019-11-29 18:00  Purple_wzy  阅读(174)  评论(0编辑  收藏  举报