点击这里查看原题
首先可以考虑,除了2和5之外,
10k
不是任何素数的倍数,因此可以先解决p不为2或5的情况。对从每个位置开始的到末尾结束的子串求一下模p的值,再离散化一下(因为题目没有给出p的范围),这样的话如果两个位置i,j模p的值相同,那么S[i…j-1]就是符合条件的一个子串。莫队处理即可
再来考虑下2和5的情况,可以发现,如果某个数是2或5的倍数,那么它的个位一定也是2或5的倍数,于是前缀和处理即可。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int M=1e5+5;
int q,pos[M],n,cnt[M],tot;
bool vis[M];
char s[M];
ll res[M],ans[M],now,v[M],t[M],p;
struct no{
int l,r,id;
bool operator<(const no &b)const{
return pos[l]==pos[b.l]?r<b.r:pos[l]<pos[b.l];
}
}qu[M];
void solve1(){
for(int i=1;i<=n;i++){
res[i]=res[i-1];
cnt[i]=cnt[i-1];
if((s[i]-'0')%p==0){
res[i]+=i;
cnt[i]++;
}
}
while(q--){
int l,r;
scanf("%d%d",&l,&r);
ll tmp=res[r]-res[l-1]-(ll)(cnt[r]-cnt[l-1])*(l-1);
printf("%lld\n",tmp);
}
}
void update(int x){
now-=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2;
if(!vis[x]) cnt[v[x]]++;
else cnt[v[x]]--;
vis[x]^=1;
now+=(ll)(cnt[v[x]]-1)*cnt[v[x]]/2;
}
int main(){
scanf("%lld%s%d",&p,s+1,&q);
n=strlen(s+1);
if(p==2||p==5){
solve1();
return 0;
}
for(int i=1,block=sqrt(n)+0.5;i<=n;i++) pos[i]=(i-1)/block+1;
ll x=0,fac=1;
for(int i=n,x=0,fac=1;i;i--){
x=(x+(ll)(s[i]-'0')*fac)%p;
fac=(ll)fac*10%p;
v[i]=t[i]=x;
}
v[++n]=t[n]=0;
sort(t+1,t+n+1);
tot=unique(t+1,t+n+1)-t-1;
for(int i=1;i<=n;i++) v[i]=lower_bound(t+1,t+tot+1,v[i])-t;
for(int i=1;i<=q;i++){
scanf("%d%d",&qu[i].l,&qu[i].r);
qu[i].r++;
qu[i].id=i;
}
sort(qu+1,qu+q+1);
int l=1,r=0;
for(int i=1;i<=q;i++){
for(int j=l;j<qu[i].l;j++) update(j);
for(int j=r;j>qu[i].r;j--) update(j);
for(int j=l-1;j>=qu[i].l;j--) update(j);
for(int j=r+1;j<=qu[i].r;j++) update(j);
l=qu[i].l,r=qu[i].r;
ans[qu[i].id]=now;
}
for(int i=1;i<=q;i++) printf("%lld\n",ans[i]);
return 0;
}