E1-B-Hope Is the Thing With Feathers

基本思路

可以考虑寻找 d_{i}k_{i} 和 d_{i}(k_{i}+1) , a 数组中小于 d_{i}(k_{i}+1) 的元素个数减去小于 d_{i}k_{i} 的元素个数即可得到

法一

容易想到的是先对数组进行排序,再进行二分查找,代码如下:

#include <stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>

#define L 1000000

int cmp(const void *a,const void *b) {
    return *(int*)a-*(int*)b;//根据需要换成(double *),(char *)
}
int  binsearch(int key[ ], int n, int k)
{
    int low=0, high=n-1, mid;
    while (low<=high) {             // 查找结束的条件
        mid=(low+high)/2;
        if(k==key[mid])
            return mid;             /*  查找成功  */
        if(k>key[mid])
            low=mid+1;            /*  准备查找后半部分 */
        else
            high=mid-1;           /* 准备查找前半部分 */
    }
    return high;                             /*   查找失败  */
}

int arr[L];

int main(){
    int n,q,d,k;
    scanf("%d%d",&n,&q);
    for(int i=0;i<n;i++){
        scanf("%d",&arr[i]);
    }
    qsort(arr,n, sizeof(int),cmp);
    while (q--){
        scanf("%d%d",&d,&k);
        int num=d*k,ans;
        int place= binsearch(arr,n,num-1);
        if(place==-1)
            place=0;
        while (arr[place]<=num-1 && place<=n-1)
            place++;
        int place2= binsearch(arr,n,num+d-1);
        while (arr[place2]<=num+d-1 &&place2<=n-1)
            place2++;
       if(place>=place2)
           ans=0;
       else
           ans=place2-place;
        printf("%d\n",ans);
    }
}

这段代码有两点需要注意的:

1.在二分查找函数中,如果没有寻找到对应元素,则返回小的下标 high ,使得我们始终能进行范围的定位

2.搜寻过程中并不是直接找 d_{i}k_{i} 和 d_{i}(k_{i}+1) ,而是都减了1,这样是为了方便统一之后的操作

法二

采用法一的方法容易超时,所以我们不妨看看如何进行优化。

注意到a的范围较小,且都是整数,因此可以考虑计数排序统计频率得到 pre 数组,之后通过前缀和让 pre[i] 表示为小于等于i的数出现的频率和

实现代码如下:

#include <stdio.h>
#include<string.h>
#include<math.h>
#include<stdlib.h>
#include<ctype.h>

int n,q;
#define N 1001001
int a[N],pre[N];

long long min(long long a,long long b){
    return a<b ? a : b;
}
long long max(long long a,long long b){
    return a>b ? a : b;
}

int main(){
    scanf("%d%d",&n,&q);
    for(int i=0;i<n;i++){
        scanf("%d",&a[i]);
        pre[a[i]]++;
    }
    for(int i=1;i<N;i++){
        pre[i]+=pre[i-1];
    }
    while (q--){
        int d,k;
        scanf("%d%d",&d,&k);
        int l=min(1ll*d*k,1ll*N);
        int r=min(1ll*d*k+d,1ll*N);
        printf("%d\n",pre[r-1]-pre[max(0,l-1)]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值