路飞&上楼

众所周知,路飞有一个神奇的能力,就是可以把他的腿无限伸长(因为他吃了橡胶果实

image.png


现在他的眼前有n个楼梯,每个楼梯都比上一次高ai​(地面从0开始)如果路飞的腿长比楼梯的高度差小的话,他就跨不过这个楼梯,他想知道,在他的腿的长度为k的时候,他最多能到达的高度为多少?(路飞目前的高度是0)。

输入描述

第一行包含一个整数t(1≤t≤100)——测试用例的数量。
每个测试用例的第一行包含两个整数n,q(1≤n,q≤2⋅105)——分别为楼梯的数量和询问的次数。
每个测试用例的第二行包含n个整数(1≤ai​≤109)—每个楼梯和上一个的高度差。
每个测试用例的第三行包含q个整数(0≤ki​≤109)——每次路飞的腿的长度。
保证n的总和不超过2⋅105,q的总和不超过2⋅105。

输出描述

对于每个测试用例,
一行进行q次回答
输出每次路飞的腿长的对应的能够到达的最高的楼梯的长度。

用例输入 1 

2
4 5
1 2 1 5
1 2 4 9 10
2 2
1 1
0 1

用例输出 1 

1 4 4 9 9 
0 2 

提示

考虑第一个样例,如图所示。
如果路飞的腿长是1,那么他只能爬第1级楼梯,所以他能爬到的高度最高是1米。
如果路飞的腿长度为2或4,那么他只能爬第1、2、3级楼梯,所以他能爬到的高度最高是1+2+1=4米。
如果路飞的腿长是9或10,那么他可以爬上整个楼梯,所以他能爬到的最高的高度是1+2+1+5=9米。

image.png

来源

NYOJ

这道题刚开始用暴力做的,超时了,然后想的是动态规划dp re了原因是这个数据范围太大了数组开不了这莫大的空间,最后想到是二分真是万万没想到。

这道题的解题思路:首先将路飞的腿的长从小到大排序,然后依次算出路飞腿长能爬倒最高楼层把他们依次存到数组ans里最后进行二分查找废话不多说直接上代码。

#include<bits/stdc++.h>
using namespace std;
int a[200005],b[200005],k[200005];
long long ans[200005];
int main()
{
    int t;
    cin>>t;
    while(t--)
    { memset(ans,0,sizeof(ans));
int n,q;
    cin>>n>>q;
    for(int i=1;i<=n;i++)
        cin>>a[i];
        for(int i=1;i<=q;i++)
        {
            cin>>k[i];
            b[i]=k[i];
        }
        sort(b+1,b+q+1);
        long long t=1;
        long long sum=0;
        for(int i=1;i<=q;i++)
        {
            for(int j=t;j<=n;j++)
            {
                if(b[i]>=a[j])
                {
                    sum=sum+a[j];
                    if(j==n)//这一步爬到了最高楼层后面爬的最高楼层都一样了
                    {
                        t=n+1;
                    }
                }
                
                else//如果腿没内长就跳出循环保留当前的位置
                {
                    t=j;
                    break;
                }
            }
            ans[i]=sum;//把每个能爬到最高楼层依次存到数组中
        }
      
        
     
     for(int i=1;i<=q;i++)
    {int l=1,r=q;
        int mid; 
	  while(l<=r)
     {
          mid=(l+r)/2;
         if(b[mid]>k[i])
         {
             r=mid-1;
         }
         else if(b[mid]<k[i])
         {
             l=mid+1;
         }
         else
         break;
     }
     cout<<ans[mid]<<" ";
	 }
     cout<<endl;
    }
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值