bzoj2506: calc
考虑离线,首先可以把每个询问的区间转化成[1,x]的形式
然后对询问的右端点排序
接着从左往右扫,记录每个数出现的次数,以及模数小于100的所有结果出现的次数
对于P小于100的询问,直接得到答案
对于P大于100的询问,暴力枚举得到答案
复杂度O(nsqrt(n))
#include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #define N 233333 using namespace std; inline int read(){ int ret=0;char ch=getchar(); while (ch<'0'||ch>'9') ch=getchar(); while ('0'<=ch&&ch<='9'){ ret=ret*10-48+ch; ch=getchar(); } return ret; } int a[N],n; struct query{ int pos,P,mod,id; query(){} query(int _pos,int _P,int _mod,int _id):pos(_pos),P(_P),mod(_mod),id(_id){} } q[N]; bool operator <(const query &x,const query &y){ return x.pos<y.pos; } int ans[N],cnt[23333],res[233][333]; int main(){ n=read();int Q=read(),m=0; for (int i=1;i<=n;++i) a[i]=read(); for (int i=1;i<=Q;++i){ int x=read(),y=read(),z=read(),tmp=read(); q[++m]=query(x-1,z,tmp,-i); q[++m]=query(y,z,tmp,i); } sort(q+1,q+m+1); int j=1; memset(cnt,0,sizeof(cnt)); memset(res,0,sizeof(res)); memset(ans,0,sizeof(ans)); for (int i=1;i<=m;++i){ for (;j<=q[i].pos;++j){ ++cnt[a[j]]; for (int k=1;k<=100;++k) ++res[k][a[j]%k]; } int now=0; if (q[i].P>100) for (int k=0;k*q[i].P+q[i].mod<=10000;++k) now+=cnt[k*q[i].P+q[i].mod]; else now=res[q[i].P][q[i].mod]; ans[abs(q[i].id)]+=q[i].id/abs(q[i].id)*now; } for (int i=1;i<=Q;++i) printf("%d\n",ans[i]); return 0; }