1. 程式人生 > >Educational Codeforces Round 51 (Rated for Div. 2)E. Vasya and Big Integers(二分雜湊+差分)

Educational Codeforces Round 51 (Rated for Div. 2)E. Vasya and Big Integers(二分雜湊+差分)

題目傳送門

題意

  給出長度小於等於10610^6的數字串a,l,r,求把串a拆分後,每段數字大小都是l\geq l並且r\leq r的方案有多少種。

分析

  首先我們可以發現一個很顯然的結論,即如果從第i位開始截成一段,那麼這一段的可行的右端點一定是一個連續的區間。那麼我們可以想到一個O(len2)O(len^2)的DP,就是對於串a,預處理出兩個陣列la,ra,表示如果從第i位開始切成一段,那麼這一段的結尾可以落在la[i]jra[i]la[i]\leq j \leq ra[i]中,令f[i]f[i]表示前i位劃分合法的方案數,那麼對於每一位從前往後,這一位對後面的貢獻就是f

[j]+=f[i](la[i]jra[i])f[j]+=f[i](la[i]\leq j\leq ra[i]),最後答案就是f[len]f[len]了。   考慮如何加速找到陣列la,ra的這個過程,我們知道我們比較兩個長度相等的大整數的時候,是從高位開始逐位比較,直到比到不一樣的一位或者當前位置超過了某一個整數的位數,根據這個想法,我們可以考慮對於串a,對於每一位求出從第i位開始對串l和串r的lcp是多少,然後我們就可以比較出可行的範圍了。求lcp的這個過程我們可以用預處理O(n)O(n)每一位詢問O(1)O(1)的Exkmp或SA,或者使用二分雜湊,每一位查詢是O(log)O(log)的,也是可以通過的。由於f[i]f[i]對後面的位置的答案是連續一段的,所以我們就可以通過差分搞定這個區間加,這樣的話這題就做完了,我用了二分雜湊,然後由於是Edu,怕被卡雜湊,就用了三模雜湊,常數略微大了點,總複雜度是O(nlogn)O(n logn)的,700ms AC。

Code

#pragma GCC optimize("3","Ofast","inline")
#include<bits/stdc++.h>
#define _ 0
using namespace std;
template<class T>inline void read(T &x) { x=0;T f=1;char ch=getchar(); while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();} while(isdigit(ch))x=x*10+ch-48,ch=getchar(); x*=f; } inline int Add(const int &x,const int &y,const int &mod) { int res=x+y; return res>=mod?res-mod:res; } inline int Sub(const int &x,const int &y,const int &mod) { int res=x-y; return res<0?res+mod:res; } inline int Mul(const int &x,const int &y,const int &mod) { return 1ll*x*y%mod; } inline int Pow(int x,int y,const int &mod) { int res=1; while(y) { if(y&1) res=Mul(res,x,mod); x=Mul(x,x,mod); y>>=1; } return res; } const int base=10,M=998244353; char a[1000005],l[1000005],r[1000005]; int la,ll,lr; struct Hash { int numa[1000005],numl[1000005],numr[1000005],mod,inv[1000005],fac[1000005]; inline void init(const int &m) { mod=m; int P=1e6; fac[0]=1; for(int i=1;i<=P;++i) fac[i]=Mul(fac[i-1],base,mod); inv[P]=Pow(fac[P],mod-2,mod); for(int i=P-1;~i;--i) inv[i]=Mul(inv[i+1],base,mod); for(int i=la;i;--i) numa[i]=Add(numa[i+1],Mul(fac[la-i],a[i]-'0',mod),mod); for(int i=ll;i;--i) numl[i]=Add(numl[i+1],Mul(fac[ll-i],l[i]-'0',mod),mod); for(int i=lr;i;--i) numr[i]=Add(numr[i+1],Mul(fac[lr-i],r[i]-'0',mod),mod); // cout<<"Now mod = "<<mod<<endl; // for(int i=1;i<=la;++i) // cout<<numa[i]<<" "; // cout<<endl; // for(int i=0;i<10;++i) // cout<<inv[i]<<" "; // cout<<endl; } inline int calca(const int &l,const int &r) { return Mul(Sub(numa[l],numa[r+1],mod),inv[la-r],mod); } inline int calcl(const int &l,const int &r) { return Mul(Sub(numl[l],numl[r+1],mod),inv[ll-r],mod); } inline int calcr(const int &l,const int &r) { return Mul(Sub(numr[l],numr[r+1],mod),inv[lr-r],mod); } }H1,H2,H3; inline int solvel(const int &p,const int &l) { return H1.calca(p,p+l-1)==H1.calcl(1,l)&&H2.calca(p,p+l-1)==H2.calcl(1,l)&&H3.calca(p,p+l-1)==H3.calcl(1,l); } inline int solver(const int &p,const int &l) { return H1.calca(p,p+l-1)==H1.calcr(1,l)&&H2.calca(p,p+l-1)==H2.calcr(1,l)&&H3.calca(p,p+l-1)==H3.calcr(1,l); } inline int lcpl(const int &p) { int l=0,r=min(ll,la-p+1),mid,ans=0; while(l<=r) { int mid=(l+r)>>1; if(solvel(p,mid)) l=mid+1,ans=mid; else r=mid-1; } return ans; } inline int lcpr(const int &p) { int l=0,r=min(lr,la-p+1),mid,ans=0; while(l<=r) { int mid=(l+r)>>1; if(solver(p,mid)) l=mid+1,ans=mid; else r=mid-1; } return ans; } int f[1000005],g[1000005]; int main() { scanf("%s%s%s",a+1,l+1,r+1); la=strlen(a+1),ll=strlen(l+1),lr=strlen(r+1); H1.init(998244353),H2.init(993244853),H3.init(1000000007); // cout<<H1.calca(1,2)<<" "<<H2.calca(1,2)<<" "<<H3.calca(1,2)<<" "<<H1.calcr(1,1)<<endl; g[0]=1; for(int i=0;i<=la;++i) { int pl=i+1,pr=i+1; if(i) g[i]=f[i]=Add(f[i],f[i-1],M); if(i==la) break; if(a[i+1]=='0') { if(l[1]!='0') pr=pl-1; } else { int j=i+1,p=lcpl(j); // cout<<"Pos :"<<j<<" "<<p<<endl; if(p==ll) pl=j+ll-1; else if(a[j+p]>l[p+1]) pl=j+ll-1; else if(a[j+p]<l[p+1]) pl=j+ll; p=lcpr(j); // cout<<"Pos :"<<j<<" "<<p<<endl; if(p==lr) pr=j+lr-1; else if(a[j+p]>r[p+1]) pr=j+lr-2; else if(a[j+p]<r[p+1]) pr=j+lr-1; } // cout<<"Now at:"<<i<<" Value :"<<f[i]<<" Trans :"<<pl<<" -> "<<pr<<endl; f[pl]=Add(f[pl],g[i],M),f[pr+1]=Sub(f[pr+1],g[i],M); // for(int j=0;j<=la;++j) // cout<<f[j]<<" "; // cout<<endl; // for(int j=0;j<=la;++j) // cout<<g[j]<<" "; // cout<<endl; } printf("%d\n",g[la]); return ~~(0^_^0); }