(n1e5)
数据范围这么小,莫队啊!
(suf_i)为后缀除以p的余数
那么区间([l,r])整除(p ofrac{suf_l-suf_{r+1}}{10^{n-r}}=0)
- (gcd(10,p)=1 o suf_l=suf_{r+1})求区间([l,r+1])内相同数的对数,莫队,时间复杂度(O(nsqrt 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])<<"
";
}
}
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]<<"
";
return (0-0);
}