一、题目
二、解法
首先考虑一个子串
s
[
l
.
.
r
]
s[l..r]
s[l..r]能被
p
p
p整除的条件,设
a
[
i
]
a[i]
a[i]为
s
[
i
.
.
n
]
s[i..n]
s[i..n]的数模
p
p
p后的值,有:
(
a
[
l
]
−
a
[
r
+
1
]
)
÷
1
0
n
−
r
=
0
m
o
d
p
(a[l]-a[r+1])\div10^{n-r}=0\mod p
(a[l]−a[r+1])÷10n−r=0modp分类讨论,当
gcd
(
p
,
10
)
=
1
\gcd(p,10)=1
gcd(p,10)=1时,说明
a
[
l
]
=
a
[
r
+
1
]
m
o
d
p
a[l]=a[r+1]\mod p
a[l]=a[r+1]modp,可以先算出每一个后缀模
p
p
p的值,然后问题就变成了
[
l
,
r
+
1
]
[l,r+1]
[l,r+1]中相同元素对数(位置不能取相同,
n
+
1
n+1
n+1值默认为
0
0
0),莫队
O
(
n
n
)
O(n\sqrt n)
O(nn)。
当 gcd ( p , 10 ) ≠ 0 \gcd(p,10)\not=0 gcd(p,10)=0时, p = 2 o r 5 p=2\space or\space5 p=2 or 5,直接考虑末尾,维护一个末尾满足条件的位置前缀和还有个数前缀和即可,时间复杂度 O ( n ) O(n) O(n),具体可以参考代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
#define int long long
const int M = 100005;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,nn,p,sum,b[10],a[M],c[M],cnt[M],ans[M];
char s[M];
struct node
{
int l,r,id;
node(int L=0,int R=0,int I=0) : l(L) , r(R) , id(I) {}
bool operator < (const node &b) const
{
return l/nn==b.l/nn?r<b.r:l<b.l;
}
} q[M];
void add(int x,int f)
{
sum-=cnt[a[x]]*(cnt[a[x]]-1)/2;
cnt[a[x]]+=f;
sum+=cnt[a[x]]*(cnt[a[x]]-1)/2;
}
signed main()
{
p=read();
scanf("%s",s+1);
n=strlen(s+1);
m=read();
nn=sqrt(n);
if(p==2 || p==5)
{
if(p==2) b[0]=b[2]=b[4]=b[6]=b[8]=1;
if(p==5) b[0]=b[5]=1;
for(int i=1; i<=n; i++)
{
a[i]=a[i-1]+b[s[i]-'0'];
c[i]=c[i-1]+b[s[i]-'0']*i;
}
for(int i=1; i<=m; i++)
{
int l=read(),r=read();
printf("%lld\n",c[r]-c[l-1]-(a[r]-a[l-1])*(l-1));
}
return 0;
}
for(int i=n,t=1; i>=1; i--,t=t*10%p)
{
a[i]=(a[i+1]+(s[i]-'0')*t%p)%p;
c[i]=a[i];
}
n++;
sort(c+1,c+1+n);
int t=unique(c+1,c+1+n)-c-1;
for(int i=1; i<=n; i++)
{
a[i]=lower_bound(c+1,c+1+t,a[i])-c;
}
for(int i=1; i<=m; i++)
{
int l=read(),r=read();
q[i]=node(l,r+1,i);
}
sort(q+1,q+1+m);
int l=1,r=0;
for(int i=1; i<=m; i++)
{
int L=q[i].l,R=q[i].r,id=q[i].id;
while(l>L) add(--l,1);
while(r<R) add(++r,1);
while(l<L) add(l++,-1);
while(r>R) add(r--,-1);
ans[id]=sum;
}
for(int i=1; i<=m; i++)
printf("%lld\n",ans[i]);
}