NOIP提高组 同余

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 long
using 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]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值