bzoj2506 calc

题目描述

题解:

首先,将询问$(l,r)$改为$(1,r)-(1,l-1)$。

由于$p<=10000$,可以考虑对$p$分治。

若$p<=100$,我们可以存模$p$等于$k$的有多少个,次数为$100*k,k<=n$;

若$100<=p<=10000$,可以暴力枚举有哪几个数模$p$等于$k$,枚举不超过$100$次,时间复杂度最多$k*m,k<=100$。

然后就能过了……

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 100050;
template<typename T>
inline void read(T&x)
{
    T f = 1,c = 0;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();}
    x = f*c;
}
int n,m,w[N],ans[N],tot;
struct node
{
    int p,k,i,d,t;
    node(){}
    node(int p,int k,int i,int d,int t):p(p),k(k),i(i),d(d),t(t){}
}q[N<<1];
bool cmp(node a,node b){return a.d<b.d;}
int h1[105][105],h2[N];
int cot(int p,int k)
{
    if(p<=100)return h1[p][k];
    int ret = 0;
    for(;k<=10000;k+=p)
        ret += h2[k];
    return ret;
}
int main()
{
//    freopen("tt.in","r",stdin);
    read(n),read(m);
    for(int i=1;i<=n;i++)
        read(w[i]);
    for(int l,r,P,k,i=1;i<=m;i++)
    {
        read(l),read(r),read(P),read(k);
        if(l>1)q[++tot]=node(P,k,i,l-1,-1);
        q[++tot]=node(P,k,i,r,1);
    }
    sort(q+1,q+1+tot,cmp);
    for(int I=1,i=1;i<=n;i++)
    {
        h2[w[i]]++;
        for(int j=1;j<=100;j++)
            h1[j][w[i]%j]++;
        while(q[I].d==i)
        {
            ans[q[I].i]+=q[I].t*cot(q[I].p,q[I].k);
            I++;
        }
    }
    for(int i=1;i<=m;i++)
        printf("%d\n",ans[i]);
    return 0;
}
View Code

 

posted @ 2019-04-16 15:49  LiGuanlin  阅读(119)  评论(0编辑  收藏  举报