Codeforces Round #849 (Div. 4) G2.Teleporters (Hard Version) (二分,贪心)

题目大意:

考虑数字线上的点0,1,…,n+1。在点1、2、…、n中的每个点上都有一个传送器。在点i,可以执行以下操作:

向左移动一个单位:需要1个硬币。

向右移动一个单位:它需要1个硬币。

在i点使用传送机,如果它存在的话:它需要a_{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;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值