• [机房测试]蛇


    Desciption

    给定一个 (2 imes n) 的字符矩阵和一个串 (S),问 (S) 中有多少种匹配方式。

    Solution

    这题的突破口在于行数为二,那么这个匹配的路径就会呈现一定规律,从而方便 dp。具体而言,路径一定形如:

    1. 往前走 (a eq 1) 步,再掉头走 (a) 步回来。

    2. 扭动着往后走。

    3. 往后走 (b eq 1) 步,再掉头走 (b) 步回来。

    (dp[i][j][k][0/1]) 表示当前在 ((i,j)) 已经匹配到了第 (k) 位,当前是从前另一边转移的方案数。

    对于 (1) ,可以用 Hash 来与处理出一些 dp 值,对于二,有转移

    [dp[i][j][k][0] +=dp[i][j-1][k-1][0/1] \ dp[i][j][k][1] +=dp[i ext{^}1][j][k-1][0] ]

    最后再枚举 (b) ,结合 (dp) 计算答案。注意到路径可能是反着的,所以要把串翻过来再做一遍。对于 (n=1)(n=2) 要去重。

    #include<stdio.h>
    #include<string.h>
    #include<algorithm>
    using namespace std;
    
    typedef long long ll;
    
    inline int read(){
        int x=0,flag=1; char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')flag=0;c=getchar();}
        while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-48;c=getchar();}
        return flag? x:-x;
    }
    
    const int N=2e3+7;
    const int Bs=233;
    const int Mod=998244353;
    const int mod=1e9+7;
    
    ll pw[N];
    
    struct Node{
        char s[N]; int n;
        ll Hs[2][N];
        char operator [](int x){return s[x];}
        inline void in(){
            scanf("%s",s+1),n=strlen(s+1);
        }
        inline void rev(){
            reverse(s+1,s+1+n); pre();
        }
        inline void pre(){
            for(int i=1;i<=n;i++)
                Hs[0][i]=(Hs[0][i-1]*Bs%Mod+s[i])%Mod;
            for(int i=n;i;i--)
                Hs[1][i]=(Hs[1][i+1]*Bs%Mod+s[i])%Mod;
        }
        inline ll Get(int l,int r,bool op=0){
            if(!op) return (Hs[0][r]-pw[r-l+1]*Hs[0][l-1]%Mod+Mod)%Mod;
            return (Hs[1][l]-pw[r-l+1]*Hs[1][r+1]%Mod+Mod)%Mod;
        }
    }A[2],B;
    
    inline void pl(ll &x,const ll &y){
        x+=y; if(x>=mod) x-=mod;
    }
    
    int n,m;
    ll ans=0,dp[2][N][N][2];
    void calc(){
        memset(dp,0,sizeof(dp));
        for(int i=0;i<2;i++)
            for(int j=1;j<=n;j++){
                dp[i][j][1][0]=(A[i][j]==B[1]);
                for(int k=2,rg=min(m/2,j);k<=rg;k++)
                    dp[i][j][k<<1][1]=(A[i].Get(j-k+1,j,0)==B.Get(k+1,k<<1))
                                     &(A[i^1].Get(j-k+1,j,1)==B.Get(1,k));
            }
        for(int k=1;k<=m;k++)
            for(int i=0;i<2;i++)
            for(int j=1;j<=n;j++){
                if(A[i][j]!=B[k]) continue;
                pl(dp[i][j][k][0],(dp[i][j-1][k-1][0]+dp[i][j-1][k-1][1])%mod);
                pl(dp[i][j][k][1],dp[i^1][j][k-1][0]);
            }
        for(int i=0;i<2;i++)
        for(int j=1;j<=n;j++)
            for(int k=0;k<=m;k++){
                int ret=m-k;
                if((ret&1)||ret==2) continue; else ret>>=1;
                if((m==k)||((j+ret<=n)&(A[i].Get(j+1,j+ret,0)==B.Get(k+1,k+ret)) 
                  &(A[i^1].Get(j+1,j+ret,1)==B.Get(m-ret+1,m))))
                    pl(ans,(dp[i][j][k][0]+dp[i][j][k][1])%mod);
            }
    }
    
    int main(){
        freopen("snake.in","r",stdin);
        freopen("snake.out","w",stdout);
        pw[0]=1; for(int i=1;i<N;i++) pw[i]=pw[i-1]*Bs%Mod;
        A[0].in(),A[1].in(),B.in(); A[0].pre(),A[1].pre(),B.pre();
        n=A[0].n,m=B.n;
        calc(); if(m==1) return printf("%lld",ans),0;
        A[0].rev(),A[1].rev(); calc();
        if(m==2){
            for(int i=0;i<2;i++)
            for(int j=1;j<=n;j++)
                ans-=(A[i][j]==B[1]&&A[i^1][j]==B[2]);
        }
        printf("%lld",ans);
    }
    
  • 相关阅读:
    C++中的乱七八糟问题
    在Win环境下配置java的环境进行开发步骤
    常用软件破解
    关于QT建立项目中遇到的相关问题的处理办法
    QT5.4.0安装以及与VS2010整合安装---64bit操作系统解决方案
    STL容器之一vector
    STL
    三种初步简易的方法求解数值问题 of C++
    Visual Studio 简单使用常识操作
    江城感怀---诗一首
  • 原文地址:https://www.cnblogs.com/wwlwQWQ/p/15355155.html
Copyright © 2020-2023  润新知