题意:n个非负整数a[n],m个询问,l,r,p,k,问l<=i<=r且a[i]%p=k的数的个数。
数据范围:
0<n,m<=10^5,任意1<=i<=n满足Ai<=10^4,0<p<=10^4,0<=k<p。
将询问离线,将[l,r]分为[1,l-1]和[1,r],同时记录a[i]对100以内的数的模数和a[i]的数量,然后对p>100和p<=100分别按两种记录方式得到结果,这样保证了查询时间复杂度为O(100m)
#include<bits/stdc++.h>
using namespace std;
int n, m, top, mx;
int a[100005];
int f1[105][105], f2[100005];
int ans[2][100005];
struct data1 { int x, f, p, k, num; }q[200005];
inline bool cmp(data1 a, data1 b)
{
return a.x < b.x;
}
void add(int x)
{
for (int i = 1; i <= 100; i++)
f1[i][x % i]++;
f2[x]++;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
cin>>a[i], mx = max(mx, a[i]);
for (int i = 1; i <= m; i++)
{
int l, r, p, k;
scanf("%d%d%d%d", &l, &r, &p, &k);
q[++top].x = l - 1; q[top].p = p; q[top].k = k; q[top].num = i;
q[++top].x = r; q[top].p = p; q[top].k = k; q[top].num = i; q[top].f = 1;
}
sort(q + 1, q + top + 1, cmp);
int now = 0;
for (int i = 1; i <= top; i++)
{
while (now < q[i].x) { now++; add(a[now]); }
int p = q[i].p, k = q[i].k;
if (p <= 100)ans[q[i].f][q[i].num] = f1[p][k];
else
for (int j = k; j <= mx; j += p)
ans[q[i].f][q[i].num] += f2[j];
}
for (int i = 1; i <= m; i++)
printf("%d\n", ans[1][i] - ans[0][i]);
return 0;
}