题意:求一个数字串在模p意义下,子串表示的数等于m的个数(p为质数)
暴力想法:O(n2)枚举子串,O(n2)预处理每个串代表的数字,O(1)判断
预处理空间不够,改为O(n)预处理每个后缀f[i],需要的串[i,j)即为(dfrac{f[i]-f[j]}{10^{n-j+1}})
也就是我们需要
(dfrac{f_i-f_j}{10^{n-j+1}}equiv mmod p)
同乘(10^{n-j+1})后移项,左侧是仅含有i的式子,右侧是仅含有j的式子
(f_iequiv 10^{n-j+1}m+f_jmod p)
开桶存f[i]%p出现次数,O(1)统计,复杂度O(n),非常美好
然后这样就Wrong Answer了
举个例子:
(1 otequiv2mod 5)
同乘10
(10equiv20mod5)
问题在哪?如果反过来看俩式子,显然就错了,从来没人说过“同除”这样的性质啊
也就是同乘性确实成立,但我一直理解成充要条件了,明知没有“同除性”这样的东西,也就说明了它只是充分的(对于一个对的式子)
怎么才能充要呢?当乘的数(perp)p即可
所幸p是质数,需要乘的数只是10的k次幂,只含有2或5,所以特判一下2或5即可(这俩数正好也很好特判)
哎..
#include<bits/stdc++.h>
using namespace std;
inline int rd(){
int ret=0,f=1;char c;
while(c=getchar(),!isdigit(c))f=c=='-'?-1:1;
while(isdigit(c))ret=ret*10+c-'0',c=getchar();
return ret*f;
}
#define pc putchar
#define space() pc(' ')
#define nextline() pc('
')
void pot(int x){if(!x)return;pot(x/10);pc('0'+x%10);}
void out(int x){if(!x)pc('0');if(x<0)pc('-'),x=-x;pot(x);}
typedef long long ll;
const int MAXN = 500005;
char S[MAXN];
int f[MAXN],b[MAXN],s[MAXN];
int n,p,m;
int sh[MAXN];
int mul(int x,int y){
ll xx=x,yy=y;
ll ret=(xx*yy)%p;
return (int)ret;
}
void spsolve(){
ll ans=0;
for(int i=1;i<=n;i++){
if(s[i]%p==m) ans+=i;
}
cout<<ans;
}
int main(){
scanf("%s",S+1);
p=rd();m=rd();
n=strlen(S+1);
for(int i=1;i<=n;i++) s[i]=S[i]-'0';
if(p==5||p==2) return spsolve(),0;
sh[0]=1;
for(int i=1;i<=n+1;i++) sh[i]=(sh[i-1]*10)%p;
ll ans=0;
for(int i=n;i>=1;i--)
f[i]=(f[i+1]+(sh[n-i]*s[i])%p)%p;
for(int i=1;i<=n+1;i++){
ans+=1ll*b[(f[i]+mul(m,sh[n-i+1]))%p];
b[f[i]%p]++;
}
cout<<ans<<endl;
return 0;
}