\(n1e5\)
数据范围这么小,莫队啊!
\(suf_i\)为后缀除以p的余数
那么区间\([l,r]\)整除\(p\to\frac{suf_l-suf_{r+1}}{10^{n-r}}=0\)
- \(gcd(10,p)=1\to suf_l=suf_{r+1}\)求区间\([l,r+1]\)内相同数的对数,莫队,时间复杂度\(O(n\sqrt n)\)
- 否则,2,5的倍数用看末尾数,时间复杂度\(O(n)\)
推式子!!
#include<bits/stdc++.h>
using namespace std;
#define int long long
inline int read(){
int x=0,f=1;char c=getchar();
while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
return f==1?x:-x;
}
const int N=1e5+4,B=500;
int n,m,p,c[N],s[N],ans[N];
char ch[N];
inline void work(){
for(int i=1;i<=n;i++){
if((p==2&&!((ch[i]^48)&1))||(p==5&&((ch[i]^48)==0||(ch[i]^48)==5))){
s[i]=i;
c[i]=1;
}
s[i]+=s[i-1];
c[i]+=c[i-1];
}
while(m--){
static int l,r;
l=read();r=read();
cout<<s[r]-s[l-1]-(l-1)*(c[r]-c[l-1])<<"\n";
}
}
struct ques{
int l,r,id;
}q[N];
inline bool comp(const ques &x,const ques &y){
return x.l/B==y.l/B?x.r<y.r:x.l/B<y.l/B;
}
signed main(){
p=read();
scanf("%s",ch+1);
n=strlen(ch+1);
m=read();
if(p==2||p==5){work();return (0-0);}
for(int i=1;i<=m;i++){
q[i].l=read();q[i].r=read()+1;
q[i].id=i;
}
sort(q+1,q+m+1,comp);
for(int i=n,mi=1;i;i--,(mi*=10)%=p)
c[i]=s[i]=((ch[i]^48)*mi+s[i+1])%p;
sort(c+1,c+n+2);
int cn=unique(c+1,c+n+2)-c-1;
for(int i=1;i<=n+1;i++)
s[i]=lower_bound(c+1,c+cn+1,s[i])-c;
memset(c,0,sizeof(c));
for(int i=1,l=1,r=0,nw=0;i<=m;i++){
while(r<q[i].r){
++r;
nw+=c[s[r]];
++c[s[r]];
}
while(q[i].r<r){
--c[s[r]];
nw-=c[s[r]];
--r;
}
while(l<q[i].l){
--c[s[l]];
nw-=c[s[l]];
++l;
}
while(q[i].l<l){
l--;
nw+=c[s[l]];
c[s[l]]++;
}
ans[q[i].id]=nw;
}
for(int i=1;i<=m;i++)cout<<ans[i]<<"\n";
return (0-0);
}