Description

一个\(2*n\)的方格矩阵,每个格子里有一个字符

给定一个长度为\(m\)的字符串\(s\)

求在方格矩阵中,有多少种走法能走出字符串\(s\)

一种合法的走法定义为:从任意一个位置出发,每次只能走到相邻的格子(common side),一个格子不能经过多次

\(n,m\le 2000\)

Analysis

刚做完一道百度之星题,跟这题很像,都是一个\(n^2​\)的dp

考虑从一个格子出发的走法:

比如一开始往右走,走若干步,往下,设当前走了\(k\)步

此时如果往右走,那么左边有一堵墙,还需走后\(m-k\)步

如果往左,就只能一直往左,走到中途匹配完,或者走回到起点的下面,然后往左走一步,那么右边有一堵墙,还需走后\(m-2k\)步

一开始往下走或往左走同理,都能经过一些简单的转化最后变成一个有墙的问题

而对于有墙的问题,dp就没有后效性了,一个简单的dp即可

我们求出每个格子出发,左边有墙的,走完后\(k\)的字符的方案数,往左出发同理求

最后在扫一遍统计从每个格子出发的方案数

字符串匹配用hash即可

Code

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cctype>
#include <cmath>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
const int M=2e3+7;
const int Q=1e9+7; inline int pls(int x,int y){return (x+y)%Q;}
inline int mns(int x,int y){return pls(x,Q-y);}
inline int mul(int x,int y){return 1LL*x*y%Q;} int n,m;
char s[2][M],t[M];
int l[M][2][M],r[M][2][M];
bool bl[M][2][M],br[M][2][M]; struct Hsh{
static const int W=131; ull lf[M],rt[M],pw[M]; ull lfhsh(int x,int len){ int y=x+len-1;
return lf[y]-lf[x-1]*pw[len];
} ull rthsh(int len,int y){ int x=y-len+1;
return rt[x]-rt[y+1]*pw[len];
} void init(char *s,int n){ int i;
for (pw[0]=1,i=1;i<=n;++i) pw[i]=pw[i-1]*W;
for (lf[0]=0,i=1;i<=n;++i) lf[i]=lf[i-1]*W + s[i]-'a';
for (rt[n+1]=0,i=n;i>0;--i) rt[i]=rt[i+1]*W + s[i]-'a';
}
}hs[2],ht; void solve(){ int i,j,k; for(i=n;i>0;--i)
for(j=0;j<2;++j)
for(k=2;k<=m;k+=2)
br[i][j][k]= (i+k/2-1<=n && hs[j].lfhsh(i,k/2)==ht.lfhsh(m-k+1,k/2) && hs[j^1].rthsh(k/2,i+k/2-1)==ht.lfhsh(m-k/2+1,k/2)); for(i=1;i<=n;++i)
for(j=0;j<2;++j)
for(k=2;k<=m;k+=2)
bl[i][j][k]= (i-k/2+1>=1 && hs[j].rthsh(k/2,i)==ht.lfhsh(m-k+1,k/2) && hs[j^1].lfhsh(i-k/2+1,k/2)==ht.lfhsh(m-k/2+1,k/2)); r[n+1][0][0]=r[n+1][1][0]=1;
for(i=n;i>0;--i)
for(j=0;j<2;++j)
for(r[i][j][0]=1,k=1;k<=m;++k){
if(s[j][i]==t[m-k+1]) r[i][j][k]=pls(r[i][j][k],r[i+1][j][k-1]);
if(k>2 && s[j][i]==t[m-k+1] && s[j^1][i]==t[m-k+2]) r[i][j][k]=pls(r[i][j][k],r[i+1][j^1][k-2]);
if(br[i][j][k]) r[i][j][k]=pls(r[i][j][k],1);
} l[0][0][0]=l[0][1][0]=1;
for(i=1;i<=n;++i)
for(j=0;j<2;++j)
for(l[i][j][0]=1,k=1;k<=m;++k){
if(s[j][i]==t[m-k+1]) l[i][j][k]=pls(l[i][j][k],l[i-1][j][k-1]);
if(k>2 && s[j][i]==t[m-k+1] && s[j^1][i]==t[m-k+2]) l[i][j][k]=pls(l[i][j][k],l[i-1][j^1][k-2]);
if(bl[i][j][k]) l[i][j][k]=pls(l[i][j][k],1);
} for(i=n;i>0;--i)
for(j=0;j<2;++j)
for(k=2;k<=m;k+=2)
br[i][j][k]= (i+k/2-1<=n && hs[j].lfhsh(i,k/2)==ht.lfhsh(1,k/2) && hs[j^1].rthsh(k/2,i+k/2-1)==ht.lfhsh(k/2+1,k/2)); for(i=1;i<=n;++i)
for(j=0;j<2;++j)
for(k=2;k<=m;k+=2)
bl[i][j][k]= (i-k/2+1>=1 && hs[j].rthsh(k/2,i)==ht.lfhsh(1,k/2) && hs[j^1].lfhsh(i-k/2+1,k/2)==ht.lfhsh(k/2+1,k/2)); int ans=0;
for(i=1;i<=n;++i)
for(j=0;j<2;++j){
if(s[j][i]==t[1]) {ans=pls(ans,pls(l[i-1][j][m-1],r[i+1][j][m-1]));if(m==1) ans=mns(ans,1);}
for(k=2;k<=m;k+=2){
if(bl[i][j][k]) ans=pls(ans,r[i+1][j^1][m-k]);
if(br[i][j][k]) ans=pls(ans,l[i-1][j^1][m-k]);
}
if(m==2&&bl[i][j][2]) ans=mns(ans,1);
}
printf("%d\n",ans);
} int main(){ int i; scanf("%s",s[0]+1);
scanf("%s",s[1]+1);
scanf("%s",t+1); n=strlen(s[0]+1); m=strlen(t+1);
hs[0].init(s[0],n);
hs[1].init(s[1],n);
ht.init(t,m); solve(); return 0;
}

cf 613E - Puzzle Lover的更多相关文章

  1. CF613E Puzzle Lover

    题意 英文版题面 Problems Submit Status Standings Custom test .input-output-copier { font-size: 1.2rem; floa ...

  2. [Codeforces613E]Puzzle Lover

    Problem 给你2*n的格子,每个格子有一个字母,从任意一点出发,不重复的经过上下左右,生成要求的字符串.问有几种不同的走法. Solution 分三段,左U型.中间.右U型. 分别枚举左边和右边 ...

  3. 题解 CF613E Puzzle Lover

    解题思路 其实仔细观察我们可以发现路径一定是一个类似于下图的一个左括号之后中间随便反复曲折,然后右边在来一个右括号. 然后对于两个括号形状的东西其实是可以利用 Hash 来判等特殊处理的. 对于中间的 ...

  4. cf Round 613

    A.Peter and Snow Blower(计算几何) 给定一个点和一个多边形,求出这个多边形绕这个点旋转一圈后形成的面积.保证这个点不在多边形内. 画个图能明白 这个图形是一个圆环,那么就是这个 ...

  5. codeforces613E

    Puzzle Lover CodeForces - 613E Oleg Petrov loves crossword puzzles and every Thursday he buys his fa ...

  6. 多校联训 DP 专题

    [UR #20]跳蚤电话 将加边变为加点,方案数为 \((n-1)!\) 除以一个数,\(dp\) 每种方案要除的数之和即可. 点击查看代码 #include<bits/stdc++.h> ...

  7. CF 634A Island Puzzle

    A. Island Puzzle time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...

  8. CF 914 D. Bash and a Tough Math Puzzle

    D. Bash and a Tough Math Puzzle http://codeforces.com/contest/914/problem/D 题意: 单点修改,每次询问一段l~r区间能否去掉 ...

  9. CF 936C Lock Puzzle——构造

    题目:http://codeforces.com/contest/936/problem/C 玩了一个小时,只能想出 5*n 的方法. 经过一番观察?考虑这样构造:已经使得 A 串的一个后缀 = B ...

随机推荐

  1. Oracle数据库学习(二)

    2.用SQL进行多表查询 (1)无条件多表查询 笛卡尔集:总记录数=table1记录数×table2记录数 select * from table1, table2 (2)等值连接 内连接:selec ...

  2. js获取整型数组最大值、最小值、平均值

    ---恢复内容开始--- let values = [];//数组(整型数字) //获取数组最大值function arrMaxNum(arr){ var maxNum = null; for (va ...

  3. 用户和用户组以及 Linux 权限管理

    1.从 /etc/passwd 说起 前面的基本命令学习中,我们介绍了使用 passwd 命令可以修改用户密码.对于操作系统来说,用户名和密码是存放在哪里的呢?我们都知道一个站点的用户名和密码是存放在 ...

  4. PHP跨域请求nodejs

    摘要:用nodejs作为服务器,php作为客服端进行跨域请求,并返回数据. 一:windows环境下的nodejs安装(以及express模板的安装):http://blog.uifanr.com/2 ...

  5. dijkstra与他的优化!!!

    目录 SPFA已死,有事烧纸 Dijkstra 配对堆 引言 讲解 合并 修改 弹出堆顶pop 代码 结合! 1 2 @ SPFA已死,有事烧纸 其实我本人也是一个SPFA的忠诚用户,至少我的最少费用 ...

  6. makefile学习(1)

    GNU Make / Makefile 学习资料 GNU Make学习总结(一) GNU Make学习总结(二) 这篇学习总结,从一个简单的小例子开始,逐步加深,来讲解Makefile的用法. 最后用 ...

  7. docker 学习(1)

    Docker与容器和虚拟机 Docker跟虚拟机有什么区别啊?这个问题可以拆成两部分.因为Docker并不是什么完全独创的技术,而是属于很早便有了的容器技术,所以第一个问题就是容器与虚拟机的区别?同属 ...

  8. Java并发模型框架

    构建Java并发模型框架 Java的多线程特性为构建高性能的应用提供了极大的方便,但是也带来了不少的麻烦.线程间同步.数据一致性等烦琐的问题需要细心的考虑,一不小心就会出现一些微妙的,难以调试的错误. ...

  9. Git的安装及常用操作

    一.Git的安装 1.下载Git,官网地址为:https://git-scm.com/downloads.     2.下载完成之后,双击目录进行安装 3.选择安装目录 4.选择组件,默认即可 5.设 ...

  10. 【Next Permutation】cpp

    题目: Implement next permutation, which rearranges numbers into the lexicographically next greater per ...