【CF】gym D. Firecrackers (二分)

题目链接:

https://codeforces.com/contest/1468/problem/D

考虑一条长长的走廊,它可以被分成大小为 1×1 的 n  个正方形单元格。这些单元格从左到右依次编号为 1 至 n 。

走廊上有两个人,一个小流氓和一个保安。一开始,流氓在 ath单元,保安在 bth单元( a≠b )。

 其中一种可能的情况。走廊由 77 个牢房组成,流氓在 33 个牢房里,保安在 66 个牢房里( n=7 , a=3 , b=6 )。

流氓的口袋里有 m 个鞭炮, i 个鞭炮在点燃后的 si 秒内爆炸。

以下事件每秒都会发生(按顺序,完全按以下顺序):

  1. 首先,流氓要么移动到相邻的牢房(从 i 号牢房,他可以移动到 (i+1) 号牢房或 (i−1) 号牢房,并且不能离开走廊),要么留在当前牢房。如果流氓不移动,他可以点燃**个鞭炮并扔掉。流氓不能进入守卫所在的牢房; 其次,一些已经扔下的鞭炮可能会爆炸。从形式上来说,如果 j 的鞭炮是在 Tth秒扔下的,那么它就会在 (T+sj)th秒爆炸(例如,如果 sj=2 的鞭炮是在 4th秒扔下的,那么它就会在 6th秒爆炸);
  2. 最后,警卫移动一个牢房靠近流氓。如果警卫移动到流氓所在的牢房,流氓就会被抓住。

显然,流氓迟早会被抓住,因为走廊是有限的。他的目标是在被抓之前看到最大数量的鞭炮爆炸;也就是说,他的行动是为了在被抓之前看到最大数量的鞭炮爆炸。

你的任务是计算出如果流氓的行为是最优的,那么这种鞭炮的数量是多少。

输入

第一行包含一个整数 t ( 1≤t≤1000 ) - 测试用例的数量。

每个测试用例由两行组成。第一行包含四个整数 n 、 m 、 a 和 b ( 2≤n≤109 ; 1≤m≤2⋅105 ; 1≤a,b≤n ; a≠b )。( 2≤n≤109 ; 1≤m≤2⋅105 ; 1≤a,b≤n ; a≠b )--分别是走廊的大小、鞭炮的数量、流氓的初始位置和警卫的初始位置。

第二行包含 m 个整数 s1 、 s2 、......、 sm( 1≤si≤109 )。( 1≤si≤109 ),其中 si�� 是 i� 个鞭炮点燃后爆炸所需的时间。

保证所有测试用例的 m 之和不超过 2⋅105 。

输出

对于每个测试用例,打印一个整数--流氓在被抓之前最多可以引爆的鞭炮数量。

在第一个测试案例中,流氓的行为举例如下:

  • 第二步 1:放下第二个鞭炮,让它在 5th 秒爆炸。警卫移动到 5 格;
  • 第二个 2:移动到 2 格。守卫移动到 4 格;
  • 第二个 3: 扔下第一个鞭炮,让它在第 4 秒爆炸。守卫移动到 3 格;
  • 第二个 4: 移动到 1 格。第一个鞭炮爆炸。守卫移动到 2 格;
  • 第二个 5:留在 1 格。第二个鞭炮爆炸。守卫移动到 1 牢房,抓住流氓。

 思想

首先将炸弹爆炸时间从小到达排序,因为肯定优先选择爆炸时间快的.

如果x个炸弹可以成功,那么x-1个也一定能成功,满足单调性,因此可以二分.

二分炸弹要引爆的数量mid,那么肯定是选择e[1,mid],因为前mid个爆炸时间最短,
同时,在点燃和逃跑过程中,容易想到一定是先点燃完这mid个炸弹,
然后将剩下的时间全部用来逃跑拖时间,
因此check就是判断点燃+跑的过程中是否会被抓到.

一个小细节是:
因为我们目标是点燃这mid个炸弹,那么我们一定是先点燃e[mid],然后点燃e[mid-1],最后e[1],
因为跑的过程中炸弹也会计时,逆序点燃才能使得所有炸弹爆炸的总时间最少.
 

代码

// Problem: D. Firecrackers
// Contest: Codeforces - 2020-2021 ICPC, NERC, Southern and Volga Russian Regional Contest (Online Mirror, ICPC Rules)
// URL: https://codeforces.com/contest/1468/problem/D
// Memory Limit: 512 MB
// Time Limit: 4000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int N = 2e6+5;

int n,m,a,b;
int t[N];

bool check(int mid){
	int x=a,y=b;
	int baozha=0;
	for(int i=mid;i>=1;i--){
		if(y>x) y--;
		else y++;
		baozha--;
		baozha=max(baozha,t[i]);
		if(x==y) return 0;
	}
	
	int pao=0;
	if(x<y) pao=y-1;
	else pao=n-y;
	return baozha<=pao;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);

	int T;
	cin>>T;
	while(T--){
		cin>>n>>m>>a>>b;
		for(int i=1;i<=m;i++){
			cin>>t[i];
		}
		
		sort(t+1,t+m+1);
		int res=0;
		int l=1,r=m;
		while(l<=r){
			int mid=(l+r)/2;
			if(check(mid)){
				res=mid;
				l=mid+1;
			}
			else r=mid-1;
		}
		cout<<res<<"\n";
		
	}
	
	
	return 0;	

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值