题目大意
给你一个长度为
n
的序列,有
n≤104
m≤105
0≤q<p≤104
ai≤104
解题思路
首先对于一个区间
[l,r]
的询问,我们显然可以用
[1,r]
中符合要求的个数减去
[1,l−1]
中符合要求的个数,这样就可以将一个询问拆成两个询问,然后从
1
到
对于一个模数
p
,我们很难直接处理询问,那么我们考虑将
1.
p≤maxai−−−−−√
:对于这种情况由于
p
最多只有
2.
p≥maxai−−−−−√
:其实每次询问相当于找都多少个
ak
满足
ak=p∗t+q
,由于
p≥maxai−−−−−√
,所以符合要求的
t
最多只有
结合两种思想总的复杂度就是 O(n∗maxai−−−−−√) 。
程序
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 1e5 + 5, MAXM = 1e4 + 5;
const int Lim = 100;
struct Node {
int side, ord, p, q, val;
Node (int a, int b, int c, int d, int e) {side = a, ord = b, p = c, q = d, val = e;}
Node () {}
};
Node Q[MAXN * 2];
int n, m, Max, num[MAXM], a[MAXN], ans[MAXN], g[Lim][Lim];
bool Cmp(Node A, Node B) {
return A.side < B.side;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i ++) {
scanf("%d", &a[i]);
Max = max(Max, a[i]);
}
int tot = 0;
for (int i = 1; i <= m; i ++) {
int l, r, p, q;
scanf("%d%d%d%d", &l, &r, &p, &q);
Q[++ tot] = Node(l - 1, i, p, q, -1);
Q[++ tot] = Node(r, i, p, q, 1);
}
sort(Q + 1, Q + tot + 1, Cmp);
int i = 1, j = 1;
for (; Q[j].side < 1; j ++);
for (; j <= tot; i ++) {
num[a[i]] ++;
for (int k = 1; k < Lim; k ++) g[k][a[i] % k] ++;
while (j <= tot && Q[j].side == i) {
if (Q[j].p < Lim) {
ans[Q[j].ord] += Q[j].val * g[Q[j].p][Q[j].q];
} else {
int t = Q[j].q;
for (; t <= Max; t += Q[j].p)
ans[Q[j].ord] += Q[j].val * num[t];
}
j ++;
}
}
for (int i = 1; i <= m; i ++)
printf("%d\n", ans[i]);
}