基本思路
可以考虑寻找 和
,
数组中小于
的元素个数减去小于
的元素个数即可得到
法一
容易想到的是先对数组进行排序,再进行二分查找,代码如下:
#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.在二分查找函数中,如果没有寻找到对应元素,则返回小的下标 ,使得我们始终能进行范围的定位
2.搜寻过程中并不是直接找 和
,而是都减了1,这样是为了方便统一之后的操作
法二
采用法一的方法容易超时,所以我们不妨看看如何进行优化。
注意到的范围较小,且都是整数,因此可以考虑计数排序统计频率得到
数组,之后通过前缀和让
表示为小于等于
的数出现的频率和
实现代码如下:
#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;
}