BJTU 1867. try a try, ac is OK

题意:求一个数字串在模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 m\mod p\)

同乘\(10^{n-j+1}\)后移项,左侧是仅含有i的式子,右侧是仅含有j的式子

\(f_i\equiv 10^{n-j+1}m+f_j\mod p\)

开桶存f[i]%p出现次数,O(1)统计,复杂度O(n),非常美好

然后这样就Wrong Answer

举个例子:

\(1\not\equiv2\mod 5\)

同乘10

\(10\equiv20\mod5\)

问题在哪?如果反过来看俩式子,显然就错了,从来没人说过“同除”这样的性质啊

也就是同乘性确实成立,但我一直理解成充要条件了,明知没有“同除性”这样的东西,也就说明了它只是充分的(对于一个对的式子)

怎么才能充要呢?当乘的数\(\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('\n')
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;
}
posted @ 2020-09-14 21:46  GhostCai  阅读(86)  评论(0编辑  收藏  举报