AtCoder Beginner Contest 164 - D Multiple of 2019
题意:给出一个由数字组成的字符串,让你求这个字符串里有多少个子串是 \(2019\) 的倍数。
很思维的一道题目
考虑 \([l,n]\) 和 \([r,n]\) 模 \(2019\) 同余 (\(l\leq r\))
设 \(x=[r,n]\),\(k=n-r+1\),\(y=[l,r)\),则可以把 \([l,n]\) 表示为 \(z=y\times 10^k+x\)。
然后因为 \(x\)、\(z\) 同余,所以 \(z-x\) 是 \(2019\) 的倍数。
即 \(y\times 10^k \equiv 0\pmod {2019}\)
然后因为 \(10^k \not \equiv 0 \pmod{2019}\)
所以 \(y\equiv 0 \pmod{2019}\)
所以 \([l,r)\) 就是 \(2019\) 的倍数了。
所以对于一个 \(l\), 我们只需要找出有多少个 \([r,n] \equiv [l,n] \pmod {2019}\),就是以 \(l\) 开头的符合要求的子串的个数了。
那么我们可以把每一个 \([i,n] \bmod 2019 (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;
}