NOIP提高组 同余

来源:互联网 发布:新侠客行 知乎 编辑:程序博客网 时间:2024/05/16 09:48

Description

这里写图片描述

Data Constraint

这里写图片描述

Solution

看到这种题(a[i]如此小),果断想到用根号级别的算法。考虑到一个合法的a[i]=kp+q,所以我们分类讨论一下p的范围。设max(a[i])=x。

1、当p>=X时,k的枚举范围不会大于X,所以直接那么用个桶存一下值为i的有几个,用O(X)时间扫一下就好了。

2、当p<X时,p的至最多也是100。这时我们用一个二维数组g[i][j]表示模i后余数为j的数的个数,直接输出就好了。

那么怎么解决区间查询的问题呢?我们将一个询问l,r,p,q拆成两个询问分别是1,l-1,p,q和1,r,p,q,然后将这2*m个询问按右端点的大小排个序,从左到右用个扫描线O(N)扫一下就好了。所以程序的总复杂度为O(NX)。

代码

#include<iostream>#include<cmath>#include<cstdio>#include<cstring>#include<algorithm>#define ll long longusing namespace std;const int maxn=100005,maxn1=105;struct code{    int a,b;}b[maxn*2];int f[maxn1][maxn1],n,m,i,x,t,j,k,l,y,mid,a[maxn],r,p[maxn],q[maxn],xx,yy,ans[maxn*2],g[maxn];bool cmp(code x,code y){    return x.a<y.a;}int pan(int x){    if (x) return x;return m;}int main(){//  freopen("data.in","r",stdin);freopen("data.out","w",stdout);    scanf("%d%d",&n,&m);    for (i=1;i<=n;i++)        scanf("%d",&a[i]);    for (i=1;i<=m;i++)        scanf("%d%d%d%d",&b[i].a,&b[i+m].a,&p[i],&q[i]),b[i].a--,b[i].b=i,b[i+m].b=i+m;    sort(b+1,b+2*m+1,cmp);r=0;    for (i=1;i<=2*m;i++){        for (j=r+1;j<=b[i].a;j++){            g[a[j]]++;            for (k=1;k<=100;k++)                f[k][a[j]%k]++;        }r=b[i].a;        t=pan(b[i].b%m);        if (p[t]<=100) ans[b[i].b]=f[p[t]][q[t]];        else{            for (k=0;k<=(maxn-q[t])/p[t];k++){                x=k*p[t]+q[t];                ans[b[i].b]+=g[x];            }        }    }    for (i=1;i<=m;i++)        printf("%d\n",ans[i+m]-ans[i]);}
3 0
原创粉丝点击