分析
我们可以从模数上面思考
我们看看,如果设一个g[i][j]表示模j为i的数的数量
那么我们每次得到一个数,模一遍,复杂度为O(np)
然后再设h[i]表示为i的数的数量
i如果模p等于q,则满足p*k+q=i
我们只需要枚举k,复杂度为O(n ai/p)
显然得知当p为根号a时最优
把询问拆成差分查询即可
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; const int N=1e5+10; int n,m; int a[N],h[100001],g[101][101],ans[N]; struct Query { int r,p,q,id,del; }q[2*N]; int cnt; bool CMP(Query a,Query b) { return a.r<b.r; } int Calc(int x) { int ans=0; if (q[x].p>=100) for (int i=0;i<=10000/q[x].p;i++) ans+=h[i*q[x].p+q[x].q]; else ans=g[q[x].q][q[x].p]; return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); for (int i=1;i<=m;i++) ++cnt,scanf("%d%d%d%d",&q[cnt].r,&q[cnt+1].r,&q[cnt].p,&q[cnt].q),q[cnt].id=i,q[cnt].del=-1,q[cnt].r--, ++cnt,q[cnt].p=q[cnt-1].p,q[cnt].q=q[cnt-1].q,q[cnt].id=i,q[cnt].del=1; sort(q+1,q+cnt+1,CMP); int j=1; while (j<=cnt&&q[j].r==0) j++; for (int i=1;i<=n;i++) { h[a[i]]++; for (int k=1;k<=100;k++) g[a[i]%k][k]++; while (j<=cnt&&q[j].r==i) { ans[q[j].id]+=q[j].del*Calc(j); j++; } } for (int i=1;i<=m;i++) printf("%d ",ans[i]); }