Codeforces 613E

令两个串分别为 s 1 s_1 s1 s 2 s_2 s2。设 F [ i ] [ j ] [ 0 / 1 ] [ 0 / 1 ] F[i][j][0/1][0/1] F[i][j][0/1][0/1]表示当前起点为 s 1 s_1 s1 s 2 s_2 s2的前/后第 j j j列(仅在前/后 j j j列中匹配),从第 i i i个位置开始匹配完 w w w的方案数,预处理一些lcp的信息即可快速计算。
再考虑计算答案。忽略仅在 s 1 s_1 s1 s 2 s_2 s2中选的平凡情况,枚举起点和第一个拐弯的位置,考虑之后是向哪个方向,简单讨论一下,都可以调用预处理的 F F F值得出方案数。
时间复杂度 O ( ∣ s ∣ ∣ w ∣ ) \mathcal O(|s||w|) O(sw)

#include <bits/stdc++.h>
#define MOD 1000000007
 
using namespace std;
 
inline void add(int &x,int y) {
  ((x+=y)>=MOD)?x-=MOD:0;
}
 
char s1[2005],s2[2005],s3[2005];
 
int lcp[2005][2005][2][2];
 
void pre(int n,int m) {
  for(int i=n;i>0;i--) {
    for(int j=1;j<=m;j++) {
    	lcp[i][j][0][0]=((s1[i]==s2[j])?lcp[i+1][j-1][0][0]+1:0);
    	lcp[i][j][1][0]=((s1[i]==s3[j])?lcp[i+1][j-1][1][0]+1:0);
    	lcp[i][j][0][1]=((s1[i]==s2[j])?lcp[i+1][j+1][0][1]+1:0);
    	lcp[i][j][1][1]=((s1[i]==s3[j])?lcp[i+1][j+1][1][1]+1:0);
	}
  }
}
 
int f[2005][2005][2][2];
 
void dp(int n,int m) {
  for(int i=0;i<=m+1;i++) f[n+1][i][0][0]=f[n+1][i][0][1]=f[n+1][i][1][0]=f[n+1][i][1][1]=1;
  for(int i=n;i>0;i--) {
    for(int j=1;j<=m;j++) {
    	if (s1[i]==s2[j]) {
    		add(f[i][j][0][0],f[i+1][j-1][0][0]);
    		if (i<n-1&&s1[i+1]==s3[j]) add(f[i][j][0][0],f[i+2][j-1][1][0]);
		}
		if (s1[i]==s3[j]) {
			add(f[i][j][1][0],f[i+1][j-1][1][0]);
    		if (i<n-1&&s1[i+1]==s2[j]) add(f[i][j][1][0],f[i+2][j-1][0][0]);
		}
	}
	for(int j=m;j>0;j--) {
    	if (s1[i]==s2[j]) {
    		add(f[i][j][0][1],f[i+1][j+1][0][1]);
    		if (i<n-1&&s1[i+1]==s3[j]) add(f[i][j][0][1],f[i+2][j+1][1][1]);
		}
		if (s1[i]==s3[j]) {
			add(f[i][j][1][1],f[i+1][j+1][1][1]);
    		if (i<n-1&&s1[i+1]==s2[j]) add(f[i][j][1][1],f[i+2][j+1][0][1]);
		}
	}
	if ((n-i)&1) {
		int len=((n-i+1)>>1);
		for(int j=len;j<=m;j++) {
			if (lcp[i][j][0][0]>=len&&lcp[i+len][j-len+1][1][1]>=len) add(f[i][j][0][0],1);
			if (lcp[i][j][1][0]>=len&&lcp[i+len][j-len+1][0][1]>=len) add(f[i][j][1][0],1);
		}
		for(int j=m-len+1;j>0;j--) {
			if (lcp[i][j][0][1]>=len&&lcp[i+len][j+len-1][1][0]>=len) add(f[i][j][0][1],1);
			if (lcp[i][j][1][1]>=len&&lcp[i+len][j+len-1][0][0]>=len) add(f[i][j][1][1],1);
		}
	}
  }
}
 
int solve(int n,int m) {
  int ans=0;
  for(int i=1;i<=m;i++) {
    if (lcp[1][i][0][0]>=n) add(ans,1);
    if (lcp[1][i][1][0]>=n) add(ans,1);
    if (lcp[1][i][0][1]>=n) add(ans,1);
    if (lcp[1][i][1][1]>=n) add(ans,1);
  }
  for(int i=1;i<=m;i++) {
  	if (s1[1]==s2[i]) {
  		int t=lcp[1][i][0][1];
  		for(int j=1;j<=min(t,n-1);j++)
  		  if (s1[j+1]==s3[i+j-1]) {
  		  	  if (j<n-1) add(ans,f[j+2][i+j][1][1]);
  		  	  if (n-j<=j) {
  		  	  	    if (lcp[j+1][i+j-1][1][0]>=n-j) add(ans,1);
				  }
			  else if (lcp[j+1][i+j-1][1][0]>=j) add(ans,f[(j<<1)+1][i-1][1][0]);
			}
		t=lcp[1][i][0][0];
		for(int j=2;j<=min(t,n-1);j++)
		  if (s1[j+1]==s3[i-j+1]) {
		  	  if (j<n-1) add(ans,f[j+2][i-j][1][0]);
		  	  if (n-j<=j) {
		  	  	    if (lcp[j+1][i-j+1][1][1]>=n-j) add(ans,1);
				}
			  else if (lcp[j+1][i-j+1][1][1]>=j) add(ans,f[(j<<1)+1][i+1][1][1]);
		  }
	  }
	if (s1[1]==s3[i]) {
  		int t=lcp[1][i][1][1];
  		for(int j=1;j<=min(t,n-1);j++)
  		  if (s1[j+1]==s2[i+j-1]) {
  		  	  if (j<n-1) add(ans,f[j+2][i+j][0][1]);
  		  	  if (n-j<=j) {
  		  	  	    if (lcp[j+1][i+j-1][0][0]>=n-j) add(ans,1);
				  }
			  else if (lcp[j+1][i+j-1][0][0]>=j) add(ans,f[(j<<1)+1][i-1][0][0]);
			}
		t=lcp[1][i][1][0];
		for(int j=2;j<=min(t,n-1);j++)
		  if (s1[j+1]==s2[i-j+1]) {
		  	  if (j<n-1) add(ans,f[j+2][i-j][0][0]);
		  	  if (n-j<=j) {
		  	  	    if (lcp[j+1][i-j+1][0][1]>=n-j) add(ans,1);
				}
			  else if (lcp[j+1][i-j+1][0][1]>=j) add(ans,f[(j<<1)+1][i+1][0][1]);
		  }
	}
  }
  return ans;
}
 
int main() {
  scanf("%s%s%s",s2+1,s3+1,s1+1);
  int n=strlen(s1+1),m=strlen(s2+1);
  if (n==1) {
  	int ans=0;
  	for(int i=1;i<=m;i++) {
  		if (s2[i]==s1[1]) ans++;
  		if (s3[i]==s1[1]) ans++;
	  }
	printf("%d\n",ans);
	return 0;
  }
  pre(n,m);
  dp(n,m);
  printf("%d\n",solve(n,m));
  return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值