CF今天好像挂了in queue了评测都有5页。
下面的代码通过了校内OJ的测试,应该没什么问题,好像数据就是从CF上扒下来的来着
考虑合法的路径一定满足左边一个 U U U,右边一个 U U U,中间是蛇形。
枚举左边合法的 U U U和中间的每个格子进行转移, f [ 0 / 1 ] [ i ] [ j ] f[0/1][i][j] f[0/1][i][j]表示当前在 ( 0 / 1 , i ) (0/1,i) (0/1,i)这个格子,匹配了前 j j j个的方案数。
统计答案考虑枚举右边的 U U U就行了。
然后考虑反着再匹配一次。
注意一下要避免长度为 2 2 2的重复统计,细节有点多。。。
代码:
#include<bits/stdc++.h> #define ll long long #define re register #define cs const using std::cerr; using std::cout; typedef std::pair<int,int> pii; #define fi first #define se second cs int N=2e3+20,mod=1e9+7; inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);} inline int dec(int a,int b){a-=b;return a+(a>>31&mod);} inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;} inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;} inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;} inline void Mul(int &a,int b){a=mul(a,b);} cs int bs1=5,bs2=1147859; int pw1[N],pw2[N]; inline void init(){ pw1[0]=pw2[0]=1; for(int re i=1;i<N;++i) pw1[i]=mul(pw1[i-1],bs1), pw2[i]=mul(pw2[i-1],bs2); } class HASH{ private: char s[N]; int pre1[N],pre2[N],suf1[N],suf2[N]; public: int len; char operator[](int o){return s[o];} void read(){ scanf("%s",s+1);len=strlen(s+1); for(int re i=1;i<=len;++i){ pre1[i]=add(mul(pre1[i-1],bs1),s[i]); pre2[i]=add(mul(pre2[i-1],bs2),s[i]); } for(int re i=len;i;--i){ suf1[i]=add(mul(suf1[i+1],bs1),s[i]); suf2[i]=add(mul(suf2[i+1],bs2),s[i]); } } pii get(int l,int r){ if(l<=r) return pii(dec(pre1[r],mul(pre1[l-1],pw1[r-l+1])),dec(pre2[r],mul(pre2[l-1],pw2[r-l+1]))); else return pii(dec(suf1[r],mul(suf1[l+1],pw1[l-r+1])),dec(suf2[r],mul(suf2[l+1],pw2[l-r+1]))); } }s0,s1,t; int n,m,ans; int f[2][N][N]; signed main(){ #ifdef zxyoi freopen("string.in","r",stdin); #endif init(); s0.read(),s1.read(),t.read(); n=s0.len,m=t.len; f[0][n+1][0]=f[1][n+1][0]=1; for(int re i=n;i;--i){ f[0][i][0]=f[1][i][0]=1; for(int re k=2;k*2<=m&&i+k-1<=n;++k){ auto t1=s0.get(i,i+k-1),t2=s1.get(i,i+k-1); auto t3=t.get(m,m-k+1),t4=t.get(m-k*2+1,m-k); if(t1==t3&&t2==t4)f[1][i][k*2]=1; if(t2==t3&&t1==t4)f[0][i][k*2]=1; } } for(int re i=n;i;--i) for(int re k=1;k<=m;++k){ if(s0[i]==t[m-k+1])Inc(f[0][i][k],f[0][i+1][k-1]); if(s1[i]==t[m-k+1])Inc(f[1][i][k],f[1][i+1][k-1]); if(k>1&&s0[i]==t[m-k+1]&&s1[i]==t[m-k+2])Inc(f[0][i][k],f[1][i+1][k-2]); if(k>1&&s1[i]==t[m-k+1]&&s0[i]==t[m-k+2])Inc(f[1][i][k],f[0][i+1][k-2]); } for(int re i=1;i<=n+1;++i){ Inc(ans,f[0][i][m]); Inc(ans,f[1][i][m]); for(int re k=2;k*2<=m&&k<i;++k){ auto t1=s0.get(i-k,i-1),t2=s1.get(i-k,i-1); auto t3=t.get(k,1),t4=t.get(k+1,k*2); if(t1==t3&&t2==t4)Inc(ans,f[1][i][m-2*k]); if(t2==t3&&t1==t4)Inc(ans,f[0][i][m-2*k]); } } if(m==1){ cout<<ans<<"\n"; return 0; } memset(f,0,sizeof f); f[0][n+1][0]=f[1][n+1][0]=1; for(int re i=n;i;--i){ f[0][i][0]=f[1][i][0]=1; for(int re k=2;k*2<m&&i+k-1<=n;++k){ auto t1=s0.get(i,i+k-1),t2=s1.get(i,i+k-1); auto t3=t.get(1,k),t4=t.get(k*2,k+1); if(t1==t3&&t2==t4)f[1][i][k*2]=1; if(t2==t3&&t1==t4)f[0][i][k*2]=1; } } for(int re i=n;i;--i){ for(int re k=1;k<=m;++k){ if(s0[i]==t[k])Inc(f[0][i][k],f[0][i+1][k-1]); if(s1[i]==t[k])Inc(f[1][i][k],f[1][i+1][k-1]); if(m>2&&k>1&&s0[i]==t[k]&&s1[i]==t[k-1])Inc(f[0][i][k],f[1][i+1][k-2]); if(m>2&&k>1&&s1[i]==t[k]&&s0[i]==t[k-1])Inc(f[1][i][k],f[0][i+1][k-2]); } } for(int re i=1;i<=n+1;++i){ Inc(ans,f[0][i][m]); Inc(ans,f[1][i][m]); for(int re k=2;k+k<m&&k<i;++k){ auto t1=s0.get(i-k,i-1),t2=s1.get(i-k,i-1); auto t3=t.get(m-k+1,m),t4=t.get(m-k,m-k*2+1); if(t1==t3&&t2==t4)Inc(ans,f[1][i][m-k*2]); if(t2==t3&&t1==t4)Inc(ans,f[0][i][m-k*2]); } } cout<<ans<<"\n"; return 0; }