BJTU 1867. try a try, ac is OK
阿新 • • 發佈:2020-09-14
題意:求一個數字串在模p意義下,子串表示的數等於m的個數(p為質數)
暴力想法:O(n^2)列舉子串,O(n^2)預處理每個串代表的數字,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; }