题目链接
给出一个序列,和一些询问,每个询问包含一个整数q,问序列中乘积不小于q的数对有多少对
(代码更容易看懂)
因为q最多是3e6,所以只要统计一下序列中哪些数出现过,出现过多少次,然后用一个二重循环 ij 遍历 1−>3e6 ,当 i∗j>3e6 时 break ,这样可以统计出,乘积为 i∗j 的数对个数,再做一个累加,就可以的到乘积小于等于 i∗j 的有多少个。可证这个复杂度是
然后对输入查表,用总数减去乘积小于q的数量就得到答案。
PS:也可以先读入数据, i∗j 只遍历到询问中最大的那个数,可能会快一点,但是要一个额外的数组来存询问。
#include
using namespace std;
typedef long long ll;
const int maxn = 3e6+10;
ll num[maxn];
ll sum[maxn];
int main(){
ll n,m;
scanf("%I64d", &n);
ll ma = 0;
for(int i = 0 ; i < n ; i++){
scanf("%I64d",&m);
num[m]++;
ma = max(ma,m);
}
for(int i = 0 ; i <= ma ; i ++){
for(int j = 0 ; j <= ma; j ++){
if(1LL*i*j > 3e6) break;
sum[i*j] += num[i] * num[j];
if(i == j) sum[i*j] -= num[i];
}
}
for(int i = 1 ; i < maxn ; i ++) sum[i] += sum[i-1];
scanf("%I64d",&m);
for(int i = 0 ; i < m ; i ++){
ll tmp;
scanf("%I64d", &tmp);
printf("%I64d\n", n*(n-1) - sum[tmp-1]);
}
}