[CF1051E Vasya and Big Integers](Problem - E - Codeforces)

sb的做法

单调队列乱整(

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5,MOD=998244353;
int n,len1,len2;
string s,l,r;
int q[N],st=1,ed,us=1;
bool ck_l(string t){
	if(t.size()<l.size()) return true;
	if(t.size()>l.size()) return false;
	return t<l;
}
bool ck_r(string t){
	if(t.size()<r.size()) return false;
	if(t.size()>r.size()) return true;
	return t>r;
}
bool check(int st,int ed){
	string t=s.substr(st,ed-st+1);
//	cout<<st<<" "<<ed<<" "<<t<<" "<<((t<l)?1:0)<<" "<<((t>r)?1:0)<<" "<<((t[0]=='0')?1:0)<<endl;
	return ck_l(t)||ck_r(t)||(t[0]=='0'&&st!=ed);
}
ll dp[N],sum=1;
int main(){
	char t;
	cin>>s,cin>>l,cin>>r;
//	cout<<"\n-------"<<r<<"------"<<endl;
	s='#'+s;
	n=s.size()-1,dp[0]=1;
	for(int i=1;i<=n;++i){
		q[++ed]=i;
		while(st<=ed&&check(q[st],i)) (sum+=-dp[q[st]-1]+MOD)%=MOD,++st;
		if(st>ed) return printf("0"),0;
		while(us<ed&&us<st) ++us,(sum+=dp[q[us]-1])%=MOD;
		while(us+1<=ed&&!check(q[us+1],i)) ++us,(sum+=dp[q[us]-1])%=MOD;
		
		dp[i]=sum;
//		cout<<i<<" "<<st<<" "<<us<<" "<<ed<<" "<<dp[i]<<endl;
	}
	printf("%lld\n",dp[n]);
	return 0;
}

大概思路:

用一个单调队列来维护当前可以选择用来当最后一段的开头的所有下标

然后因为新加的点不一定能马上用到(因为有下限),所以除了sted外还有us

区间[st,us]就是可以用的下标

不过这是戳的,下辈子有空再弄吧。。。

正解

算出slr\(extend\),然后就可以进行\(DP\)

\(DP\)中,算出可以转移到i的下标取值范围\([l1,r1]\)

可以先得出一个大概的范围:\([i+len_l-1,i+len_r-1]\),因为当前划分出来的字符串的长度的范围为[len1,len2]

倒着\(DP\)\(dp[i]\)表示以i开头有多少种划分方式

然后如果\(s\)\(l\)不相等的第一个位置上,\(l\)较大,则说明当前划分出来的字符串的长度至少为\(len_l+1\);如果\(s\)\(l\)不相等的第一个位置上,\(r\)较小,则说明当前划分出来的字符串的长度最大为\(len_r-1\)

然后前缀和优化,这道题就G了

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e6+5,MOD=998244353;
int n,len1,len2,nxt1[N],nxt2[N],extend1[N],extend2[N];
char s[N],l[N],r[N];
void exkmp(char s[],int n,int nxt[]){
	nxt[1]=n;
	for(int i=2,a=0,p=0;i<=n;++i){
		if(i<p) nxt[i]=min(nxt[i-a+1],p-i);
		while(i+nxt[i]<=n&&s[nxt[i]+1]==s[i+nxt[i]]) ++nxt[i];
		if(i+nxt[i]>p) p=i+nxt[i],a=i; 
	}
}
void ekp(char s[],char t[],int n,int m,int nxt[],int extend[]){
	for(int i=1,a=0,p=0;i<=n;++i){
		if(i<p) extend[i]=min(nxt[i-a+1],p-i);
		while(i+extend[i]<=n&&extend[i]+1<=m&&s[i+extend[i]]==t[extend[i]+1]) ++extend[i];
		if(i+extend[i]>p) p=i+extend[i],a=i;
	}
}
ll dp[N],sum[N];
int main(){
	scanf("%s\n%s\n%s",s+1,l+1,r+1); 
	n=strlen(s+1),len1=strlen(l+1),len2=strlen(r+1);
	exkmp(l,len1,nxt1),exkmp(r,len2,nxt2);
	ekp(s,l,n,len1,nxt1,extend1),ekp(s,r,n,len2,nxt2,extend2);
	sum[n+1]=dp[n+1]=1;
	for(int i=n;i;--i){
		if(s[i]=='0') dp[i]=(l[1]=='0')*dp[i+1];
		else{
			int l1=i+len1-1,r1=i+len2-1;
			if(extend1[i]<len1&&l[extend1[i]+1]>s[i+extend1[i]]) ++l1;
			if(extend2[i]<len2&&r[extend2[i]+1]<s[i+extend2[i]]) --r1;
			r1=min(r1,n);
			if(l1>r1) dp[i]=0;
			else dp[i]=((sum[l1+1]-sum[r1+2])%MOD+MOD)%MOD;
		}
		sum[i]=(dp[i]+sum[i+1])%MOD;
	}
	printf("%lld",dp[1]);
	return 0;
}