解题思路

其实仔细观察我们可以发现路径一定是一个类似于下图的一个左括号之后中间随便反复曲折,然后右边在来一个右括号。

然后对于两个括号形状的东西其实是可以利用 Hash 来判等特殊处理的。

对于中间的部分直接 DP :

\(f_{i,j,k,0/1}\) 表示第 \(i\) 行,第 \(j\) 列,当前扫到了询问路径的第 \(k\) 个位置,并且是否可以向上或者下转移。

然后优先处理一下左括号形,这里可以维护两个 Hash 分别存储正反的 Hash 值进行判等。

接下来就 DP 处理中间曲折的部分( \(ch\) 为字符矩阵, \(s\) 为目标字符串),对于 \(ch_{i,j}=s_k\) 的情况进行转移,转移方程如下:

\[f_{i,j,k,0}=f_{i,j,k,0}+f_{i,j-1,k-1,0}+f_{i,j-1,k-1,1}
\]
\[f_{i,j,k,1}=f_{i,j,k,1}+f_{i\;xor\;1,j,k-1,0}
\]

注意转移的时候为了防止当前状态对于之后状态造成过多影响,应该把 k 的循环放在最外层。

对于一个路径而言因为是有向的,因此我们把字符串翻转之后再做一边 DP 就好了。

code

#include<bits/stdc++.h>
#define int long long
#define ull unsigned long long
#define f() cout<<"Pass"<<endl
using namespace std;
inline int read()
{
int x=0,f=1;char ch=getchar();
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*f;
}
const int N=2e3+10,mod=1e9+7;
const ull base=1331ull;
ull has[N],pre[2][N],suf[2][N],p[N<<1];
int n,m,ans,f[2][N][N<<1][2];
char ch[2][N],s[N<<1];
void Hash()
{
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
pre[i][j]=pre[i][j-1]*base+ch[i][j];
for(int i=0;i<=1;i++)
for(int j=n;j>=1;j--)
suf[i][j]=suf[i][j+1]*base+ch[i][j];
}
ull get_suf(int x,int l,int r){return suf[x][l]-suf[x][r+1]*p[r-l+1];}
ull get_pre(int x,int l,int r){return pre[x][r]-pre[x][l-1]*p[r-l+1];}
ull get_hash(int l,int r){return has[r]-has[l-1]*p[r-l+1];}
void add(int &x,int y){x+=y;if(x>=mod)x-=mod;}
void solve()
{
Hash();
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
{
f[i][j][1][0]=(ch[i][j]==s[1]);
for(int k=2;k<=min(j,m/2);k++)
if((get_hash(1,k)==get_suf(i^1,j-k+1,j))&&(get_hash(k+1,k<<1)==get_pre(i,j-k+1,j)))
f[i][j][k<<1][1]=1;
}
for(int k=1;k<=m;k++)
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
if(ch[i][j]==s[k])
{
add(f[i][j][k][0],f[i][j-1][k-1][0]+f[i][j-1][k-1][1]);
add(f[i][j][k][1],f[i^1][j][k-1][0]);
}
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
for(int k=0;k<=m;k++)
if(m-k!=2&&((k&1)==(m&1)))
add(ans,(f[i][j][k][1]+f[i][j][k][0])*(m==k||(j+(m-k)/2<=n&&get_pre(i,j+1,j+(m-k)/2)==get_hash(k+1,k+(m-k)/2)&&get_suf(i^1,j+1,j+(m-k)/2)==get_hash(k+(m-k)/2+1,m))));
}
void Special_Judge1()
{
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
ans-=(ch[i][j]==s[1]);
}
void Special_Judge2()
{
for(int i=0;i<=1;i++)
for(int j=1;j<=n;j++)
ans-=(ch[i][j]==s[1]&&ch[i^1][j]==s[2]);
}
signed main()
{
scanf("%s%s%s",ch[0]+1,ch[1]+1,s+1);
n=strlen(ch[0]+1); m=strlen(s+1);
p[0]=1; for(int i=1;i<=m;i++) p[i]=p[i-1]*base;
for(int i=1;i<=m;i++) has[i]=has[i-1]*base+s[i];
if(m==1) Special_Judge1();
if(m==2) Special_Judge2();
solve();
memset(f,0,sizeof(f));
for(int i=0;i<=1;i++) reverse(ch[i]+1,ch[i]+n+1);
solve();
printf("%lld",(ans+mod)%mod);
return 0;
}

题解 CF613E Puzzle Lover的更多相关文章

  1. CF613E Puzzle Lover

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

  2. 【题解】Puzzle [Uva1399]

    [题解]Puzzle [Uva1399] 传送门:\(\text{Puzzle [Uva1399]}\) [题目描述] 给定 \(m\) 和 \(n\),表示有 \(m\) 种不同的字符(大写字母\( ...

  3. [Codeforces613E]Puzzle Lover

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

  4. cf 613E - Puzzle Lover

    Description 一个\(2*n\)的方格矩阵,每个格子里有一个字符 给定一个长度为\(m\)的字符串\(s\) 求在方格矩阵中,有多少种走法能走出字符串\(s\) 一种合法的走法定义为:从任意 ...

  5. 多校联训 DP 专题

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

  6. cf Round 613

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

  7. codeforces613E

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

  8. ZOJ 1602 Multiplication Puzzle(区间DP)题解

    题意:n个数字的串,每取出一个数字的代价为该数字和左右的乘积(1.n不能取),问最小代价 思路:dp[i][j]表示把i~j取到只剩 i.j 的最小代价. 代码: #include<set> ...

  9. 题解【POJ1651】Multiplication Puzzle

    Description The multiplication puzzle is played with a row of cards, each containing a single positi ...

随机推荐

  1. hfctfwp(re)

    1.easy python revering 看字节码操作,昂哥直接看直接写exp太强了,我就直接手动写了个源码出来(昂哥永远滴神) arr0=[249,91,149,113,16,91,53,41, ...

  2. IDA PRO:庆祝成立创新 30 周年

    今天,IDA 已经三十岁了.为了纪念周年纪念,我们将描述史诗旅程的开始和主要里程碑. 背景 在 1990 年代初期,DOS 是最流行的 PC 操作系统,主要是 8086,偶尔有 80286(80386 ...

  3. 《Do Neural Dialog Systems Use the Conversation History Effectively? An Empirical Study》

    https://zhuanlan.zhihu.com/p/73723782 请复制粘贴到markdown 查看器查看! Do Neural Dialog Systems Use the Convers ...

  4. Spring常见异常说明

    文章要点 Spring bean 的声明方式 Spring bean 的注入规则 Spring bean 的依赖查找规则 Spring bean 的名称定义方式和默认名称规则 XXX required ...

  5. postgresql行列转换

    --安装扩展 CREATE EXTENSION tablefunc --使用CROSSTAB函数 SELECT * FROM CROSSTAB('SELECT 主键, 需转换的列名, 需转换的列值 F ...

  6. C++ 继承及委托

    从内存角度看继承和多重继承 http://www.doc88.com/p-9075148832569.html 在C++中实现委托(Delegate) https://blog.csdn.net/jf ...

  7. golang开发:Error的使用

    Error是Go语言开发中最基础也是最重要的部分,跟其他语言的try catch的作用基本一致,想想在PHP JAVA开发中,try catch 不会使用,或者使用不灵活,就无法感知到程序运行中出现了 ...

  8. C语言:自增 自减

    一个整数类型的变量自身加 1 可以这样写: a = a + 1; 或者 a += 1; 不过,C语言还支持另外一种更加简洁的写法,就是: a++; 或者 ++a; 这种写法叫做自加或自增,意思很明确, ...

  9. Java-数组有关

    1.复制数组 复制数组主要有三类方法: 1.使用循环语句逐个赋值数组元素 2.使用System类中的静态方法arraycopy 3.使用clone方法复制数组 对于2,详述如下: arraycopy( ...

  10. 测试开发【提测平台】分享3-正式开发产品需求&项目初始化

    上两个分享主要是介绍和演示基本前后端所要使用的框架,接下来我们将正式进入到[提测平台的开发] 提要先给出依赖和内容点: 提测平台定义和产品原型需求说明 使用github创建代码仓库进行项目管理 Fla ...