列表

详情


NC218839. 单词

描述

牛牛在学竞赛,但是由于学校领导的担心,要求牛牛在兼顾竞赛的情况下天天花分钟早读,牛牛看到一长串的英文单词差点晕了,但是突然想出了一个问题,但是他不会做,所以他想请教一下你。
有两个单词,他们非常的长,牛牛想将第一个单词提取出若干个区间,使得每一个区间都包含第二个单词,问这样提取组合的方案数。
题目中“提取出若干个区间”指的是选出若干个区间,并且这些区间互不相交。
比如说单词,其中一种提取组合就是,提取出来的字符串就是
容易发现一个单词的提取组合一共有种。

输入描述

两行每行一个单词

输出描述

一行一个整数表示方案数对取模的结果

示例1

输入:

baba
ba

输出:

7

说明:

{空集},\{[1,2],[3,4]\},\{[1,2]\},\{[3,4]\},\{[1,3]\},\{[1,4]\},\{[2,4]\}

示例2

输入:

ababaaabababaaaabaaaababa
aba

输出:

78791

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++(g++ 7.5.0) 解法, 执行用时: 46ms, 内存消耗: 20952K, 提交时间: 2022-10-25 20:14:56

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+6,M=998244353,P=99824353;
using ll=long long;
char A[N],B[N];
int a[N],_b,pw[N],n,m,L[N],f[N],g[N];
int gs(int l,int r){
	return (a[r]+M-ll(a[l-1])*pw[r-l+1]%M)%M;
}
int main(){
	scanf("%s%s",A+1,B+1);
	n=strlen(A+1),m=strlen(B+1);
	if(n<m){puts("0");return 0;}
	int i,x,y;
	for(i=pw[0]=1;i<=n;++i)pw[i]=41719ll*pw[i-1]%M;
	for(x=1;x<=n;++x)a[x]=(41719ll*a[x-1]+A[x])%M;
	for(x=1;x<=m;++x)_b=(41719ll*_b+B[x])%M;
	for(x=1;x<=n-m+1;++x)
		if(gs(x,x+m-1)==_b)
			L[x+m-1]=x;
	for(x=1;x<=n;++x)if(L[x]<L[x-1])L[x]=L[x-1];
	f[0]=g[0]=1;
	for(x=1;x<=n;++x){
		if(L[x])f[x]=g[L[x]-1];
		f[x]=(ll(f[x])+f[x-1])%P;
		g[x]=(ll(g[x-1])+f[x])%P;
	}printf("%d\n",f[n]);
	return 0;
}

C++(clang++11) 解法, 执行用时: 32ms, 内存消耗: 17016K, 提交时间: 2021-03-06 19:34:32

#include<bits/stdc++.h>
//maddison10
using namespace std;

const int mxn=1e6+5,mdn=99824353;

int n,m;
int net[mxn],f[mxn],g[mxn],p[mxn],rr[mxn];
char s[mxn],t[mxn];

int main(){
	scanf("%s",s+1);scanf("%s",t+1);
	n=strlen(s+1);m=strlen(t+1);
	for(int i=2,j=0;i<=m;i++){
		while(j&&t[i]!=t[j+1])j=net[j];
		if(t[i]==t[j+1])j++;
		net[i]=j;
	}
	for(int i=1,j=0,ps=0;i<=n;i++){
		while(j&&s[i]!=t[j+1])j=net[j];
		if(s[i]==t[j+1])j++;
		if(j==m)ps=i-m+1,j=net[j];
		rr[i]=ps;
	}

	f[0]=g[0]=1;
	for(int i=1;i<=n;i++){
		if(rr[i])f[i]=(1ll*g[rr[i]-1]*rr[i]%mdn-p[rr[i]-1]%mdn+mdn)%mdn;
		g[i]=(g[i-1]+f[i])%mdn;
		p[i]=(p[i-1]+1ll*f[i]*i%mdn)%mdn;
	}
	cout<<g[n]<<'\n';
	return 0;
}

上一题