Posted wwlw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蛇相关的知识,希望对你有一定的参考价值。

Desciption

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

Solution

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

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

  2. 扭动着往后走。

  3. 往后走 \\(b\\neq 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\\text{^}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);
}

以上是关于蛇的主要内容,如果未能解决你的问题,请参考以下文章

插入雷蛇鼠标 2 分钟,即可获得 Windows 10 管理员权限?

100行Python代码,轻松完成贪吃蛇小游戏?

贪吃蛇游戏改运行背景颜色的C语言代码。

JS学习——贪吃蛇代码(简易版)

JS学习——贪吃蛇代码(简易版)

JS学习——贪吃蛇代码(简易版)