菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
65
0

CF613E Puzzle Lover

原创
05/13 14:22
阅读数 35789

题面传送门
为什么所有题解要用\(g\)帮助转移啊,我觉得不用吧……
随便画画图就可以发现这个一定是从起点向左走一段然后再向右不回头走再向左走一段。
然后前后两端都可以用字符串哈希搞掉。
然后中间dp即可。
具体转移因为不会回来走所以枚举前一行转移即可。
时间复杂度\(O(nm)\)
code:

#include<cstdio>
#include<cstring>
#define N 2000
#define mod 1000000007
#define mod1 998244353
#define base 131
#define re register
#define ll long long
#define I inline
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z;ll f[3][N+5][N+5],ans,sum1[N+5],sum2[N+5],sum3[N+5],sum4[N+5],ba[N+5],inv[N+5];
char s[3][N+5],a[N+5];
I ll mpow(ll x,ll y=mod1-2){ll ans=1;while(y) (y&1)&&(ans=ans*x%mod1),x=x*x%mod1,y>>=1;return ans;}
I ll find1(int x,int y){return (sum1[y]-sum1[x-1]+mod1)*inv[x-1]%mod1;}
I ll find2(int x,int y){return (sum2[x]-sum2[y+1]+mod1)*inv[n-y]%mod1;}
I ll find3(int x,int y){return (sum3[y]-sum3[x-1]+mod1)*inv[x-1]%mod1;}
I ll find4(int x,int y){return (sum4[x]-sum4[y+1]+mod1)*inv[m-y]%mod1;}
I void make(){
	int i,j,k;memset(f,0,sizeof(f));
	for(i=1;i<=n;i++) sum1[i]=(sum1[i-1]+(s[1][i]-'a'+1)*ba[i])%mod1;
	for(i=n;i;i--) sum2[i]=(sum2[i+1]+(s[2][i]-'a'+1)*ba[n-i+1])%mod1;
	for(i=1;i<=m;i++) sum3[i]=(sum3[i-1]+(a[i]-'a'+1)*ba[i])%mod1;
	for(i=m;i;i--) sum4[i]=(sum4[i+1]+(a[i]-'a'+1)*ba[m-i+1])%mod1;
	for(i=1;i<=n;i++){
		for(j=max(0,i-(m-1)/2);j<i;j++){
			f[2][i][2*(i-j)]=(find1(j+1,i)==find4(1,i-j)&&find2(j+1,i)==find4(i-j+1,2*(i-j)));
			f[1][i][2*(i-j)]=(find2(j+1,i)==find3(1,i-j)&&find1(j+1,i)==find3(i-j+1,2*(i-j)));//printf("%d %d %lld %lld %lld %lld\n",j+1,i,find2(j+1,i),find3(1,i-j),find1(j+1,i),find3(i-j+1,2*(i-j)));
		} 
	}
	for(i=0;i<=n;i++) f[1][i][0]=f[2][i][0]=1; 
	for(i=1;i<=n;i++){
		for(j=1;j<=m;j++){
			for(k=1;k<=2;k++)s[k][i]==a[j]&&(f[k][i][j]+=f[k][i-1][j-1],j>=3&&(s[3-k][i]==a[j-1])&&(f[k][i][j]+=f[3-k][i-1][j-2]),f[k][i][j]%=mod);
		}
	}
	for(i=1;i<=n;i++,ans%=mod){
		ans+=f[1][i][m]+f[2][i][m];
		for(j=i+2;j<=min(n,i+(m-1)/2);j++){
			if(find1(i+1,j)==find3(m-2*(j-i)+1,m-(j-i))&&find2(i+1,j)==find3(m-(j-i)+1,m)) ans+=f[1][i][m-(j-i)*2];
			if(find2(i+1,j)==find4(m-2*(j-i)+1,m-(j-i))&&find1(i+1,j)==find4(m-(j-i)+1,m)) ans+=f[2][i][m-(j-i)*2];
			//printf("%d %d %lld %lld %lld %lld\n",i,j,find1(i+1,j),find3(m-2*(j-i)+1,m-(j-i)),find2(i+1,j),find3(m-(j-i)+1,m));
		}
	}
}
I void swap(char &x,char &y){x^=y^=x^=y;}
int main(){
	freopen("string.in","r",stdin);freopen("string.out","w",stdout);
	re int i;scanf("%s%s%s",s[1]+1,s[2]+1,a+1);n=strlen(s[1]+1);m=strlen(a+1);
	if(m==1){
		for(i=1;i<=n;i++) ans+=(s[1][i]==a[1])+(s[2][i]==a[1]);printf("%d\n",ans);return 0;
	}
	if(m==2){
		for(i=1;i<=n;i++) {
			if(s[2][i]==a[1])ans+=(s[2][i-1]==a[2])+(s[2][i+1]==a[2])+(s[1][i]==a[2]);
			if(s[1][i]==a[1])ans+=(s[1][i-1]==a[2])+(s[1][i+1]==a[2])+(s[2][i]==a[2]);
		}
		printf("%d\n",ans);return 0;
	}
	ba[0]=inv[0]=1;for(i=1;i<=max(n,m);i++) ba[i]=ba[i-1]*base%mod1,inv[i]=inv[i-1]*mpow(base)%mod1;
	make();for(i=1;i<=m/2;i++) swap(a[i],a[m-i+1]);make();
	if(m%2==0){
		for(i=m/2;i<=n;i++)ans+=(find1(i-m/2+1,i)==find4(1,m/2)&&find2(i-m/2+1,i)==find4(m/2+1,m))+(find2(i-m/2+1,i)==find3(1,m/2)&&find1(i-m/2+1,i)==find3(m/2+1,m));
		for(i=1;i<=n-m/2+1;i++)ans+=(find1(i,i+m/2-1)==find3(1,m/2)&&find2(i,i+m/2-1)==find3(m/2+1,m))+(find2(i,i+m/2-1)==find4(1,m/2)&&find1(i,i+m/2-1)==find4(m/2+1,m));
	}
	printf("%lld\n",ans);
}

发表评论

0/200
65 点赞
0 评论
收藏
为你推荐 换一批