题意:给出一个由数字组成的字符串,让你求这个字符串里有多少个子串是 2019 2019 2019 的倍数。
很思维的一道题目
考虑 [ l , n ] [l,n] [l,n] 和 [ r , n ] [r,n] [r,n] 模 2019 2019 2019 同余 ( l ≤ r l\leq r l≤r)
设 x = [ r , n ] x=[r,n] x=[r,n], k = n − r + 1 k=n-r+1 k=n−r+1, y = [ l , r ) y=[l,r) y=[l,r),则可以把 [ l , n ] [l,n] [l,n] 表示为 z = y × 1 0 k + x z=y\times 10^k+x z=y×10k+x。
然后因为 x x x、 z z z 同余,所以 z − x z-x z−x 是 2019 2019 2019 的倍数。
即 y × 1 0 k ≡ 0 ( m o d 2019 ) y\times 10^k \equiv 0\pmod {2019} y×10k≡0(mod2019)
然后因为 1 0 k ≢ 0 ( m o d 2019 ) 10^k \not \equiv 0 \pmod{2019} 10k≡0(mod2019)
所以 y ≡ 0 ( m o d 2019 ) y\equiv 0 \pmod{2019} y≡0(mod2019)
所以 [ l , r ) [l,r) [l,r) 就是 2019 2019 2019 的倍数了。
所以对于一个 l l l, 我们只需要找出有多少个 [ r , n ] ≡ [ l , n ] ( m o d 2019 ) [r,n] \equiv [l,n] \pmod {2019} [r,n]≡[l,n](mod2019),就是以 l l l 开头的符合要求的子串的个数了。
那么我们可以把每一个 [ i , n ] m o d 2019 ( i > l ) [i,n] \bmod 2019 (i>l) [i,n]mod2019(i>l) 算出来,并对于每一种余数进行计数。
最后求出答案就好了。
代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 200010
using namespace std;
char s[N];
int ans,mod[2019];
int main()
{
scanf("%s",s+1);
int len=strlen(s+1);
mod[0]=1;
for(int i=len,x=0,cnt=1;i>=1;i--,cnt=cnt*10%2019)
{
x=((s[i]-'0')*cnt+x)%2019;
ans+=mod[x];
mod[x]++;
}
printf("%d\n",ans);
return 0;
}