题面
解法
叫权值分块感觉挺诡异的……
- 我们不妨离线处理询问,对于一个询问可以变成求解 [ 1 , r ] [1,r] [1,r]中满足条件的个数- [ 1 , l − 1 ] [1,l-1] [1,l−1]中满足条件的个数。
- 由于权值到 1 0 4 10^4 104,无法直接暴力实现。那么我们考虑将这些数分成2部分来实现。对于不超过 100 100 100的模数 p p p,记 f [ i ] [ j ] f[i][j] f[i][j]表示当前做到的数中,对 i i i取模为 j j j的数的个数。对于不超过 100 100 100的询问可以直接通过 f f f数组来查询。对于超过 100 100 100的模数 p p p,记 g [ i ] g[i] g[i]表示当前做到的数中, i i i这个数出现的次数。那么当前询问的答案即为 ∑ i = 0 g [ i p + k ] \sum_{i=0} g[ip+k] ∑i=0g[ip+k]
- 可以发现,对于上述两种情况,我们单次处理的时间复杂度均为 O ( a i ) O(\sqrt a_i) O(ai)
- 时间复杂度: O ( m a i ) O(m\sqrt a_i) O(mai)
代码
#include <bits/stdc++.h>
#define N 200010
using namespace std;
template <typename T> void chkmax(T &x, T y) {x = x > y ? x : y;}
template <typename T> void chkmin(T &x, T y) {x = x > y ? y : x;}
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
struct Node {
int x, p, k, fl, id;
bool operator < (const Node &b) const {return x < b.x;}
} b[N];
int a[N], sum[N], ans[N][2], s[110][110];
void add(int x) {
for (int i = 1; i <= 100; i++) s[i][a[x] % i]++;
sum[a[x]]++;
}
int main() {
int n, m, tot = 0, mx = 0; read(n), read(m);
for (int i = 1; i <= n; i++)
read(a[i]), chkmax(mx, a[i]);
for (int i = 1; i <= m; i++) {
int l, r, p, k;
read(l), read(r), read(p), read(k);
b[++tot] = (Node) {l - 1, p, k, 0, i};
b[++tot] = (Node) {r, p, k, 1, i};
}
sort(b + 1, b + tot + 1); int now = 1;
for (int i = 1; i <= tot; i++) {
while (now <= b[i].x) add(now++);
if (b[i].p > 100) {
for (int j = b[i].k; j <= mx; j += b[i].p)
ans[b[i].id][b[i].fl] += sum[j];
} else ans[b[i].id][b[i].fl] = s[b[i].p][b[i].k];
}
for (int i = 1; i <= m; i++) cout << ans[i][1] - ans[i][0] << "\n";
return 0;
}