-
题意:有个长度为\(n\)的*,犯人在位置\(a\),cop在位置\(b\),你每次可以向左或者向右移动一个单位,或者选择不动并在原地放一个爆竹\(i\),爆竹\(i\)在\(s[i]\)秒后爆炸,cop每次向你的位置移动一个单位,你最终一定会被抓住(因为*是有限的),问你在被抓住前,最多能看到多少爆竹爆炸.
-
题解:我们可以很容易算出最能放多少个爆竹不被cop抓住,和最晚被cop抓住的时间,然后对爆竹的爆炸时间排序,假如我们要放\(x\)个爆竹,那么很显然,最优的放法一定是在第一秒放\(s[x]\),第二秒放\(s[x-1]\),...,因为我们一定会放\(x\)个爆竹,所以爆炸所需时间长的我们要先放,后放的话可能被抓住时不会爆炸,有了这个贪心思路,接下来我们对爆炸数进行二分然后判断即可.
-
代码:
#include <bits/stdc++.h>
#define ll long long
#define fi first
#define se second
#define pb push_back
#define me memset
#define rep(a,b,c) for(int a=b;a<=c;++a)
#define per(a,b,c) for(int a=b;a>=c;--a)
const int N = 1e6 + 10;
const int mod = 1e9 + 7;
const int INF = 0x3f3f3f3f;
using namespace std;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
ll gcd(ll a,ll b) {return b?gcd(b,a%b):a;}
ll lcm(ll a,ll b) {return a/gcd(a,b)*b;}
int t;
int n,m,a,b;
int s[N];
bool check(int x,int lim){
rep(i,1,x){
if(i+s[x-i+1]>lim) return false;
}
return true;
}
int main() {
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cin>>t;
while(t--){
cin>>n>>m>>a>>b;
rep(i,1,m){
cin>>s[i];
}
sort(s+1,s+1+m);
int fin=b-1; //when is caught
int cnt=b-a-1; //nums of firecrackers
if(a>b){
fin=n-b;
cnt=a-b-1;
}
cnt=min(cnt,m);
int l=0,r=cnt;
while(l<r){
int mid=(l+r+1)>>1;
if(check(mid,fin)) l=mid;
else r=mid-1;
}
cout<<l<<'\n';
}
return 0;
}