bzoj4542 大数

Description

  小 B 有一个很大的数 S,长度达到了 N 位;这个数可以看成是一个串,它可能有前导 0,例如00009312345
。小B还有一个素数P。现在,小 B 提出了 M 个询问,每个询问求 S 的一个子串中有多少子串是 P 的倍数(0 也
是P 的倍数)。例如 S为0077时,其子串 007有6个子串:0,0,7,00,07,007;显然0077的子串007有6个子串都是素
数7的倍数。

Input

  第一行一个整数:P。第二行一个串:S。第三行一个整数:M。接下来M行,每行两个整数 fr,to,表示对S 的
子串S[fr…to]的一次询问。注意:S的最左端的数字的位置序号为 1;例如S为213567,则S[1]为 2,S[1…3]为 2
13。N,M<=100000,P为素数

Output

  输出M行,每行一个整数,第 i行是第 i个询问的答案。

可以考虑用莫队解决区间询问
对于p!=2且p!=5,预处理串的每个后缀mod p的值,若两后缀mod p相等则它们间的一段mod p=0
若p=2或5,则一个串mod p为0当且仅当末尾能被p整除
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
typedef long long lint;
lint Ans=0;
int m;
char s[100005];
struct Q{
    int l,r,id;
}q[100005];
lint ans[100005];
int b,l,p;
int mp[100005],id[100005];
inline bool operator<(const Q&a,const Q&b){
    if(id[a.l]!=id[b.l])return id[a.l]<id[b.l];
    return (a.r<b.r)!=(id[a.l]&1);
}
namespace map{
    const int P=1234577;
    lint xs[P];
    int ys[P],now=0;
    bool d[P];
    int get(lint x){
        int w=x%P;
        while(d[w]){
            if(xs[w]==x)return ys[w];
            w+=1237;
            if(w>=P)w-=P;
        }
        d[w]=1;xs[w]=x;
        return ys[w]=now++;
    }
}
int yv[100005];
inline void inc(int x){
    Ans+=yv[x]++;
}
inline void dec(int x){
    Ans-=--yv[x];
}
int main(){
    scanf("%d%s%d",&p,s+1,&m);
    l=strlen(s+1);
    b=double(l+1)/(sqrt(m+1)+1)+1;
    for(int i=1;i<=l;i++)id[i]=(i-1)/b;
    for(int i=0;i<m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    std::sort(q,q+m);
    int p10=1;
    if(p!=2&&p!=5){
        for(int i=l;i;i--){
            mp[i]=(mp[i+1]+(s[i]-48ll)*p10)%p;
            p10=p10*10ll%p;
        }
        for(int i=1;i<=l+1;i++)mp[i]=map::get(mp[i]);
    }else for(int i=1;i<=l;i++)mp[i]=(s[i]-48)%p;
    int L=1,R=0;
    if(p!=2&&p!=5)
    for(int i=0;i<m;i++){
        int l=q[i].l,r=q[i].r+1;
        while(L<l)dec(mp[L++]);
        while(L>l)inc(mp[--L]);
        while(R<r)inc(mp[++R]);
        while(R>r)dec(mp[R--]);
        ans[q[i].id]=Ans;
    }else for(int i=0,c=0;i<m;i++){
        int l=q[i].l,r=q[i].r;
        while(L<l){
            Ans-=c;
            if(!mp[L++])--c;
        }
        while(L>l){
            if(!mp[--L])++c;
            Ans+=c;
        }
        while(R<r){
            if(!mp[++R])++c,Ans+=R-L+1;
        }
        while(R>r){
            if(!mp[R--])Ans-=R-L+2,--c;
        }
        ans[q[i].id]=Ans;
    }
    for(int i=0;i<m;i++)printf("%lld
",ans[i]);
    return 0;
}
原文地址:https://www.cnblogs.com/ccz181078/p/5414625.html