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

版权声明:转载需要注明哦QwQ,地址:http://blog.csdn.net/effervescence。 https://blog.csdn.net/Effervescence/article/details/82800616

题目传送门

题意

  给出长度小于等于 1 0 6 10^6 的数字串a,l,r,求把串a拆分后,每段数字大小都是 l \geq l 并且 r \leq r 的方案有多少种。

分析

  首先我们可以发现一个很显然的结论,即如果从第i位开始截成一段,那么这一段的可行的右端点一定是一个连续的区间。那么我们可以想到一个 O ( l e n 2 ) O(len^2) 的DP,就是对于串a,预处理出两个数组la,ra,表示如果从第i位开始切成一段,那么这一段的结尾可以落在 l a [ i ] j r a [ i ] la[i]\leq j \leq ra[i] 中,令 f [ i ] f[i] 表示前i位划分合法的方案数,那么对于每一位从前往后,这一位对后面的贡献就是 f [ j ] + = f [ i ] ( l a [ i ] j r a [ i ] ) f[j]+=f[i](la[i]\leq j\leq ra[i]) ,最后答案就是 f [ l e n ] f[len] 了。
  考虑如何加速找到数组la,ra的这个过程,我们知道我们比较两个长度相等的大整数的时候,是从高位开始逐位比较,直到比到不一样的一位或者当前位置超过了某一个整数的位数,根据这个想法,我们可以考虑对于串a,对于每一位求出从第i位开始对串l和串r的lcp是多少,然后我们就可以比较出可行的范围了。求lcp的这个过程我们可以用预处理 O ( n ) O(n) 每一位询问 O ( 1 ) O(1) 的Exkmp或SA,或者使用二分哈希,每一位查询是 O ( l o g ) O(log) 的,也是可以通过的。由于 f [ i ] f[i] 对后面的位置的答案是连续一段的,所以我们就可以通过差分搞定这个区间加,这样的话这题就做完了,我用了二分哈希,然后由于是Edu,怕被卡哈希,就用了三模哈希,常数略微大了点,总复杂度是 O ( n l o g n ) 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);
}

猜你喜欢

转载自blog.csdn.net/Effervescence/article/details/82800616