「BZOJ2506」calc
Description
         给一个长度为n的非负整数序列A1,A2,…,An。现有m个询问,每次询问给出l,r,p,k,问满足l<=i<=r且Ai mod p = k的值i的个数。
Input
         第一行两个正整数n和m。
         第二行n个数,表示A1,A2,…,An。
         以下m行,每行四个数分别表示l,r,p,k。满足1<=l<=r<=n。
Output
         对于每个询问,输出一行,表示可行值i的个数。
Sample Input
 5 2
1 5 2 3 7
1 3 2 1
2 5 3 0
1 5 2 3 7
1 3 2 1
2 5 3 0
Sample Output
 2
1
1
HINT
数据范围:
0<n,m<=10^5,任意1<=i<=n满足Ai<=10^4,0<p<=10^4,0<=k<p。
Source
题解
首先将所有询问离线,然后对于每个询问分成询问1-(l-1)以及1-r两部分
然后将这些询问按照右端点排序将元素逐个加入处理
询问分成两类
p<=100和p>100
第一种可以用f1[i][j]表示加入的元素对i取模余数为j的个数
第二种用f2[i]表示大小为i的数的个数,因为p>100
只要将f[k],f[k+p],f[k+2*p]……最多100个相加即可
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; inline int read() {     int x=0;char ch=getchar();     while(ch<'0'||ch>'9')ch=getchar();     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}     return x; } int n,m,top,mx; int a[100005]; int f1[105][105],f2[100005]; int ans[2][100005]; struct data{int x,f,p,k,num;}q[200005]; inline bool cmp(data a,data 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() {     n=read();m=read();     for(int i=1;i<=n;i++)         a[i]=read(),mx=max(mx,a[i]);     for(int i=1;i<=m;i++)     {         int l=read(),r=read(),p=read(),k=read();         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; } | 
因为p>100
 
			
[…] Orz hzwer巨巨 […]