题目大意:
考虑数字线上的点0,1,…,n+1。在点1、2、…、n中的每个点上都有一个传送器。在点i,可以执行以下操作:
向左移动一个单位:需要1个硬币。
向右移动一个单位:它需要1个硬币。
在i点使用传送机,如果它存在的话:它需要硬币。并且你可以选择是传送到0点还是n+1点。一旦你使用了传送机,你就不能再使用它了。
你有c个硬币,从0点开始。你能使用的传送器最多有多少?
输入由多个测试用例组成。第一行包含整数t(1≤t≤1000)-测试用例数。测试用例的描述如下。
每个测试用例的第一行包含两个整数n和c(1≤n≤2⋅105;1≤c≤109),分别是数组的长度和硬币的数量。
以下行包含n个空间分隔的正整数a1,a2,…,an(1≤ai≤109)-使用隐形传态器的成本。
保证所有测试用例的n之和不超过2⋅105。
输出
对于每个测试用例,输出您可以使用的最大传送数。
思路:
对每一个传送点,他们的最小花费为min(ai+i,ai+n+1−i),对此进行排序,但是我们还要保证第一次是要从0点出发,因此,我们遍历每个点,使其成为第一次到达的传送点,然后,通过使用前缀和数组来处理最小花费,这样我们可以利用二分查找来查找可以到达的最大点数,此外,我们还需要注意二分查找时是否包括了第一次到达的传送点。代码如下:
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
struct node{
long long in;
long long zero_dis;
long long m;
}a[300000];
long long sum[300000];
bool cmp(node a,node b){
return a.m < b.m ;
}
int main()
{
long long t;
cin >> t;
while(t--){
long long n;
long long c;
long long ans=0;
cin >> n >> c;
for(long long i=0;i<n;i++){
cin >> a[i].in;
a[i].zero_dis=a[i].in+i+1;
a[i].m=min(a[i].zero_dis,a[i].in+(n-i));
}
sort(a,a+n,cmp);
sum[0]=a[0].m;
for(long long i=1;i<n;i++){
sum[i]=sum[i-1]+a[i].m;
}
for(long long i=0;i<n;i++){
long long new_c=c-a[i].zero_dis;
long long new_ans=0;
if(new_c<0){
continue;
}
new_ans++;
auto slogan=lower_bound(sum,sum+n,new_c);
if(*slogan>new_c){
--slogan;
}
if(slogan!=sum+n){
if(slogan>=sum+i){
new_ans--;
if(*(slogan+1)-*slogan <= a[i].m+(new_c-*slogan)&&slogan!=sum+n-1){
new_ans++;
}
}
new_ans+=(slogan-sum)+1;
}
else{
ans=n;
}
ans=max(ans,new_ans);
}
printf("%lld\n",ans);
}
return 0;
}