E1-B Hope Is the Thing With Feathers

题目描述

小A给出了n个正整数 a1a_1,…,ana_n

小A提出了q个问题。第i个问题中,小 A 会给出did_i,kik_i,他想知道有多少aj(1jn)a_j(1\leq j \leq n)满足ajdi=ki\lfloor \frac{a_j}{d_i}\rfloor=k_i

题目分析

满足ajdi=ki\lfloor\frac{a_j}{d_i}\rfloor=k_i即满足dikiaj<di(ki+1)d_i k_i\leq a_j<d_i(k_i+1)

可以考虑寻找dikid_i k_idi(ki+1)d_i(k_i+1)a数组中小于di(ki+1)d_i(k_i+1)的数总频率减去小于dikid_i k_i的数总频率即为所求。

首先想到排序后二分查找,但是容易超时,注意到a的范围较小可以考虑利用计数排序统计频率得到pre数组。之后通过前缀和让pre[i]表示为小于等于i的数出现的频率和。

aia_i最大值为1e6最小值为1

求小于dikid_i k_i的数总频率

a数组中所有数都小于dikid_ik_i时应取pre[1e6]pre[1e6],当a数组中所有数都大于dikid_ik_i时应取pre[0]pre[0],否则a数组中小于dikid_ik_i的数总频率即为pre[diki1]pre[d_ik_i-1],所以最后应取**pre[max(0,min(diki,1e6+1)1)]pre[max(0,min(d_ik_i,1e6+1)-1)]**

求小于di(ki+1)d_i(k_i+1)的数总频率

a数组中所有数都小于di(ki+1)d_i(k_i+1)时应取pre[1e6]pre[1e6] ,否则a数组中小于di(ki+1)d_i(k_i+1)的数总频率为pre[di(ki+1)1]pre[d_i(k_i+1)-1],所以最后应取**pre[min(di(ki+1),1e6+1)1]pre[min(d_i(k_i+1),1e6+1)-1]**

pre[min(di(ki+1),1e6+1)1]pre[max(0,min(diki,1e6+1)1)]pre[min(d_i(k_i+1),1e6+1)-1]-pre[max(0,min(d_ik_i,1e6+1)-1)]即为所求

  • 大数相加或相乘时可能会溢出注意使用1lllong long
  • 注意讨论dikid_ik_i较大的情况

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <stdio.h>
#define N 1001001
int n, q;
int a[N], pre[N];
long long int min(long long int a, long long int b)
{
return a < b ? a : b;
}
long long int max(long long int a, long long int b)
{
return a > b ? a : b;
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 1; 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 * k * d, 1ll * N);
int r = min(1ll * k * d + d, 1ll * N);
printf("%d\n", pre[r - 1] - pre[max(0, l - 1)]);
}
return 0;
}