1. 程式人生 > >bzoj 4277: [ONTAK2015]Cięcie 亂搞

bzoj 4277: [ONTAK2015]Cięcie 亂搞

題意

給定一個長度為k的數字串N以及三個質數p,q,r,請你將N劃分為三段非空字串,使得第一段能被p整除,第二段能被q整除,第三段能被r整除,且每一段都不含前導0。注意:單獨的0是允許的。
3<=k<=1000000,2015<=p,q,r<=100000

分析

因為p,q,r均為很大的素數,那麼如果有x|q,則必有x10|q。反之,若有x10|q則必有x|q
那麼我們可以先預處理處哪些段可以整除p,r,統計q的話就用字首和瞎搞一搞就好了。

程式碼

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring> #include<algorithm> using namespace std; typedef long long LL; const int N=1000005; int n,p,q,r,s1[N],s2[N],s3[N],t[N]; char ch[N]; int main() { scanf("%d%d%d%d",&n,&p,&q,&r); scanf("%s",ch+1); for (int i=1;i<=n;i++) s1[i]=(s1[i-1]*10+ch[i]-'0'
)%p; for (int i=n,x=1;i>=1;i--,x=x*10%r) s2[i]=(s2[i+1]+(ch[i]-'0')*x)%r; for (int i=n,x=1;i>=1;i--,x=x*10%q) s3[i]=(s3[i+1]+(ch[i]-'0')*x)%q; for (int i=2;i<=n;i++) if (!s2[i]&&(ch[i]!='0'||i==n)) t[s3[i]]++; LL ans=0; for (int i=1;i<n;i++) { if (!s2[i+1
]&&(ch[i+1]!='0'||i+1==n)) t[s3[i+1]]--; if (!s1[i]&&(ch[i]!='0'||i==1)) ans+=t[s3[i+1]]; } printf("%lld",ans); return 0; }