题目链接
题目思路
设(dp[i])表示以(i)开头的答案
首先预处理如果(i)作为区间开头,那么他的右端点最近可以到哪里
那么(s[i])可以选也可以不选
若不选(dp[i]+=dp[i-1])
若选(dp[i]+=suf[r[i]+1]+d1-r[i]+1(d1代表匹配串的长度))
不选(s[i])很容易解释
选(s[i])首先可以只有一个区间那么就是(d1-r[i]+1)
若有多个区间则为(dp[r[i]+1]+dp[r[i]+2].....+dp[n])
因为以(s[i])开头的区间可以为([i,r[i]],[i,r[i]+1]....)
用后缀和优化一下即可
代码
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
typedef long long ll;
typedef unsigned long long ull;
typedef pair<double,int> pdi;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=1e6+5,mod=99824353;
char s[maxn],t[maxn];
int r[maxn];
int suf[maxn];
ll dp[maxn];
ull pre[maxn],temp,power[maxn],base=233;
ull get_hash(int l,int r){
return pre[r]-pre[l-1]*power[r-l+1];
}
int main(){
scanf("%s %s",s+1,t+1);
int d1=strlen(s+1),d2=strlen(t+1);
power[0]=1;
for(int i=1;i<=max(d1,d2);i++){
power[i]=power[i-1]*base;
if(i<=d1){
pre[i]=pre[i-1]*base+s[i];
}
if(i<=d2){
temp=temp*base+t[i];
}
}
int pos=0;
for(int i=d1-d2+1;i>=1;i--){
if(get_hash(i,i+d2-1)==temp){
pos=i+d2-1;
}
r[i]=pos;
}
ll ans=0;
for(int i=d1;i>=1;i--){
dp[i]=dp[i+1];
if(r[i]!=0){
dp[i]+=suf[r[i]+1]%mod;
dp[i]+=d1-r[i]+1;
dp[i]%=mod;
}
suf[i]=(suf[i+1]+dp[i])%mod;
}
printf("%lld
",(dp[1]+1)%mod);
return 0;
}