[CSP-S模拟测试]:蛇(DP+构造+哈希)

题目传送门(内部题140)


输入格式

  前两行有两个长度相同的字符串,描述林先森花园上的字母。
  第三行一个字符串$S$。


输出格式

  输出一行一个整数,表示有多少种可能的蛇,对$10^9+7$取模。


样例

样例输入1:

rwby
ybwr
rwby

样例输出1:

4

样例输入2:

ooo
ooo
oo

样例输出2:

14


数据范围与提示

  对于$20\%$的数据,$n,|S|\leqslant 16$。
  对于$40\%$的数据,$n,|S|\leqslant 40$。
  对于$60\%$的数据,$n,|S|\leqslant 200$。
  对于$100\%$的数据,$1\leqslant n,|S|\leqslant 2,000$,输入中只包含小写字母。


题解

先来考虑路径蛇的路径,可以将其拆解成如下图中的三部分$\downarrow$

蛇一定是先向一个方向走$a$格,再回来;然后乱走(扭动着),然后再向另一个方向走$b$格,再回来。

一样不一样可以用哈希判断。

然后考虑$DP$,定义$dp[i]][j][k]$表示到了点$(i,j)$,匹配到了$k$的方案数。

避免出现环可以外层循环$k$。

为了方便,可以先默认向一个方向走;然后再把整张图翻转再跑一遍就好了。

注意蛇的长度为$1$和$2$的情况下需要特判。

时间复杂度:$\Theta(|S|^2)$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
const int mod=1000000007;
struct rec{int s,x,y;};
int a[2][2001],b[2001],n,s;
char ch[2001];
long long dp[2][2001][4001][2],ans;
unsigned long long hsh[2001],flag[2001]={1},has[2][2][2002];
unsigned long long ask(bool x,bool y,int l,int r){return y?has[x][y][r]-has[x][y][l+1]*flag[l-r+1]:has[x][y][r]-has[x][y][l-1]*flag[r-l+1];}
unsigned long long get(int l,int r){return hsh[r]-hsh[l-1]*flag[r-l+1];}
void work()
{
	for(int i=0;i<2;i++)
		for(int j=1;j<=n;j++)
			has[i][0][j]=has[i][0][j-1]*131+a[i][j];
	for(int i=0;i<2;i++)
		for(int j=n;j;j--)
			has[i][1][j]=has[i][1][j+1]*131+a[i][j];
	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;k<=j;k++)
				dp[i][j][k<<1][1]=(ask(i^1,1,j,j-k+1)==get(1,k))&&(ask(i,0,j-k+1,j)==get(k+1,k<<1));
		}
	for(int k=1;k<=s;k++)
		for(int i=0;i<2;i++)
			for(int j=1;j<=n;j++)
			{
				if(a[i][j]!=b[k])continue;
				dp[i][j][k][0]=(dp[i][j][k][0]+dp[i][j-1][k-1][0]+dp[i][j-1][k-1][1])%mod;
				dp[i][j][k][1]=(dp[i][j][k][1]+dp[i^1][j][k-1][0])%mod;
			}
	for(int i=0;i<2;i++)
		for(int j=1;j<=n;j++)
			for(int k=0;k<=s;k++)
			{
				int res=(s-k)>>1;
				if(!((s-k)&1)&&res!=1&&(s==k||(j+res<=n&&ask(i,0,j+1,j+res)==get(k+1,k+res)&&ask(i^1,1,j+res,j+1)==get(s-res+1,s))))
					ans=(ans+dp[i][j][k][0]+dp[i][j][k][1])%mod;
			}
}
int main()
{
	scanf("%s",ch+1);n=strlen(ch+1);
	for(int i=1;i<=n;i++)a[0][i]=ch[i]-‘a‘+1;
	scanf("%s",ch+1);
	for(int i=1;i<=n;i++)a[1][i]=ch[i]-‘a‘+1;
	scanf("%s",ch+1);s=strlen(ch+1);
	for(int i=1;i<=s;i++)
	{
		b[i]=ch[i]-‘a‘+1;
		flag[i]=flag[i-1]*131;
		hsh[i]=hsh[i-1]*131+b[i];
	}
	work();
	reverse(a[0]+1,a[0]+n+1);
	reverse(a[1]+1,a[1]+n+1);
	memset(dp,0,sizeof(dp));
	work();
	if(s==1)
	{
		for(int i=0;i<2;i++)
			for(int j=1;j<=n;j++)
				ans-=(a[i][j]==b[1]);
	}
	if(s==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);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11830973.html

时间: 2024-10-29 18:06:03

[CSP-S模拟测试]:蛇(DP+构造+哈希)的相关文章

csp-s模拟测试97

csp-s模拟测试97 猿型毕露.水题一眼秒,火题切不动,还是太菜了. $T1$看了一会儿感觉$woc$期望题$T1??$假的吧??. $T2$秒. $T3$什么玩意儿. 40 01:24:46 100 00:31:38 10 02:49:26 150 02:49:26 $T1$特判错了希望人品可以++. A. 小盆友的游戏 像题解一样构造一个函数那么这个题就是水题了. B. 花 随手$Dp$. C. 表格 $Dee$树帅但是我咕了. 酷(ひど)いよ 酷(ひど)いよ.もういっそ仆(ぼく)の体(か

模拟测试(vj)

做这份模拟测试,已经崩溃了,英文看不懂,题意理解错.到结束了只a了第一题,人生陷入了低谷,于是花了一天的时间终于把不会的弄明白了,在这里写一份总结~ T1,简单的模拟,如果打枪打中一支鸟,将这个位置设为0,并向两边扩散,注意这个位置一定要有鸟. 代码~ #include<bits/stdc++.h> using namespace std; int a[30000]; int n,m; int main() { cin>>n; for(int i=1;i<=n;i++) ci

Mock 模拟测试简介及 Mockito 使用入门

Mock 是什么 mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法.这个虚拟的对象就是mock对象.mock对象就是真实对象在调试期间的代替品. 简单的看一张图 我们在测试类 A 时,类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D.E.F 等,假如类 D.E.F 构造很耗时又或者调用很耗时的话是非常不便于测试的(比如是 DAO 类,每次访问数据库都很耗时).所以我们引入 Mock 对象. 如上图,我们将

2018冬令营模拟测试赛(三)

2018冬令营模拟测试赛(三) [Problem A]摧毁图状树 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这题没想到贪心 QwQ,那就没戏了-- 贪心就是每次选择一个最深的且没有被覆盖的点向上覆盖 \(k\) 层,因为这个"最深的没有被覆盖的点"不可能再有其它点引出的链覆盖它了,而它又

2018冬令营模拟测试赛(五)

2018冬令营模拟测试赛(五) [Problem A][UOJ#154]列队 试题描述 picks 博士通过实验成功地得到了排列 \(A\),并根据这个回到了正确的过去.他在金星凌日之前顺利地与丘比签订了契约,成为了一名马猴烧酒. picks 博士可以使用魔法召唤很多很多的猴子与他一起战斗,但是当猴子的数目 \(n\) 太大的时候,训练猴子就变成了一个繁重的任务. 历经千辛万苦,猴子们终于学会了按照顺序排成一排.为了进一步训练,picks 博士打算设定一系列的指令,每一条指令 \(i\) 的效果

2018冬令营模拟测试赛(十七)

2018冬令营模拟测试赛(十七) [Problem A]Tree 试题描述 输入 见"试题描述" 输出 见"试题描述" 输入示例 见"试题描述" 输出示例 见"试题描述" 数据规模及约定 见"试题描述" 题解 这个数据范围肯定是树上背包了. 令 \(f(i, j, k)\) 表示子树 \(i\) 中选择了 \(j\) 个节点,路径与根的连接情况为 \(k\),具体地: \(k = 0\) 时,路径的两个端点

2018-10-25 模拟测试题解

目录 问题 A: 魏传之长坂逆袭 题目描述 输入 输出 样例输入 样例输出 题解 问题 B: 蜀传之单刀赴会 题目描述 [问题描述] 输入 输出 样例输入 样例输出 题解 问题 C: 吴传之火烧连营 [题目背景] [问题描述] 输入 输出 样例输入 样例输出 [样例解释] [数据规模和约定] 题解 本篇题解也发表于zwcblog作者是同一个人 问题 A: 魏传之长坂逆袭 题目描述 众所周知,刘备在长坂坡上与他的一众将领各种开挂,硬生生从曹操手中逃了出去,随后与孙权一起火烧赤壁.占有荆益.成就霸业

noip模拟测试21

T1:折纸 这道写崩我也是没话说…… 模拟就完了,记录每次的折叠点,每次将之前的都扫一遍就完了 1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<cmath> 5 #include<algorithm> 6 #include<cstdlib> 7 #define ll long long 8 using namespace std; 9 con

[考试反思]1003csp-s模拟测试58:沉淀

稳住阵脚. 还可以. 至少想拿到的分都拿到了,最后一题的确因为不会按秩合并和线段树分治而想不出来. 对拍了,暴力都拍了.挺稳的. 但是其实也有波折,险些被卡内存. 如果内存使用不连续或申请的内存全部使用的话,切记计算内存,一点都不能开大. T1: 直接根号筛,拿map也能过. 遍历map直接begin和end啊... 1 #include<cstdio> 2 int Cnt[202]; 3 struct hash_map{ 4 int cnt,fir[10000020],l[6666666],