HDU4758 Walk Through Squares AC自动机&&dp
这道题当时做的时候觉得是数论题,包含两个01串什么的,但是算重复的时候又很蛋疼,赛后听说是字符串,然后就觉得很有可能。昨天队友问到这一题,在学了AC自动机之后就觉得简单了许多。那个时候不懂AC自动机,不知道什么是状态,因此没有想到有效的dp方法。
题意是这样的,给定两个RD串,譬如RRD,DDR这样子的串,然后现在要你向右走(R)m步,向下走(D)n步,问有多少种走法能够包含给定的两个串。
一个传统的dp思想是这样的 dp[i][j][x][y][k],表示走了i步R,j步D,x,y表示两个串各匹配了多少各,k表示的是1,2串匹配的一个4进制数(00,01,10,11,你懂的,11表示都匹配了,10表示匹配了1串)。 但是这样一来空间开不下,二来当某个点失配的时候我们不知道当前的x,y会转移到哪里,这个时候很自然的,我们就想到了AC自动机,AC自动机压入两个串只需要不超过串的总长度的结点,而且当我们在自动机上转移的时候,我们可以知道失配的时候转移到哪里。所以重新定义一下就是 dp[i][j][k][x] k表示自动机上的状态,x表示4进制数。转移的时候就考虑由当前的状态dp[i][j][k][x]转移到dp[i+1][j][nxt1][nxtx] dp[i][j+1].... 其中新的状态nxt以及对应的四进制数转移就需要根据AC自动机的失配算出来。 如果预处理出当失配时回到的那个结点感觉可能会更快一些。 我代码里多写了个dfs,主要是预处理了 到达改状态时对应的四进制数,所以转移的时候只需要或一下就可以了。
第一次做AC自动机上的dp然后 1A了,好开心!
#pragma warning(disable:4996)
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<queue>
#define maxn 2000
#define mod 1000000007
using namespace std; struct Trie
{
Trie * go[2];
Trie *fail;
int sta;
void init() {
memset(go, 0, sizeof(go)), fail == NULL;
sta = 0;
}
}pool[maxn],*root;
int tot; void insert(char *c,int type)
{
int len = strlen(c); Trie *p = root;
for (int i = 0; i < len; i++){
int ind = c[i] == 'R' ? 0 : 1;
if (p->go[ind] != NULL){
p = p->go[ind];
}
else{
pool[tot].init();
p->go[ind] = &pool[tot++];
p = p->go[ind];
}
}
p->sta |= type;
} void getFail()
{
queue<Trie*> que;
que.push(root);
root->fail = NULL;
while (!que.empty())
{
Trie *temp = que.front(); que.pop();
Trie *p = NULL;
for (int i = 0; i < 2; i++){
if (temp->go[i] != NULL){
if (temp == root) temp->go[i]->fail = root;
else{
p = temp->fail;
while (p != NULL){
if (p->go[i] != NULL){
temp->go[i]->fail = p->go[i];
break;
}
p = p->fail;
}
if (p == NULL) temp->go[i]->fail = root;
}
que.push(temp->go[i]);
}
}
}
} int dfs(Trie *x){
if (x == NULL) return 0;
return x->sta |= dfs(x->fail);
} int m, n;
int dp[120][120][240][4];
char str[120];
int main()
{
int T; cin >> T;
while (T--)
{ tot = 0; root = &pool[tot++]; root->init();
scanf("%d%d", &m, &n);
for (int i = 1; i <= 2; i++){
scanf("%s", str);
insert(str, i);
}
getFail();
for (int i = 0; i < tot; i++){
dfs(&pool[i]);
}
for (int i = 0; i <= m; i++){
for (int j = 0; j <= n; j++){
for (int k = 0; k <= tot; k++){
for (int x = 0; x < 4; x++){
dp[i][j][k][x] = 0;
}
}
}
}
dp[0][0][0][0] = 1;
for (int i = 0; i <= m; i++){
for (int j = 0; j <= n; j++){
for (int k = 0; k < tot; k++){
for (int x = 0; x < 4; x++){
Trie* p = &pool[k];
if (p->go[0] != NULL){
(dp[i + 1][j][p->go[0] - pool][x | p->go[0]->sta] += dp[i][j][k][x]) %= mod;
}
else{
Trie *temp = p->fail;
while (temp != NULL) {
if (temp->go[0] != NULL){
(dp[i + 1][j][temp->go[0] - pool][x | temp->go[0]->sta] += dp[i][j][k][x]) %= mod;
break;
}
temp = temp->fail;
}
if (temp == NULL) (dp[i + 1][j][0][x | root->sta] += dp[i][j][k][x]) %= mod;
}
if (p->go[1] != NULL){
(dp[i][j + 1][p->go[1] - pool][x | p->go[1]->sta] += dp[i][j][k][x]) %= mod;
}
else{
Trie *temp = p->fail;
while (temp != NULL) {
if (temp->go[1] != NULL){
(dp[i][j + 1][temp->go[1] - pool][x | temp->go[1]->sta] += dp[i][j][k][x]) %= mod;
break;
}
temp = temp->fail;
}
if (temp == NULL) (dp[i][j + 1][0][x | root->sta] += dp[i][j][k][x]) %= mod;
}
}
}
}
}
int ans = 0;
for (int i = 0; i < tot; i++){
ans = ans + dp[m][n][i][3]; ans %= mod;
}
printf("%d\n", ans);
}
return 0;
}
HDU4758 Walk Through Squares AC自动机&&dp的更多相关文章
- HDU 4758 Walk Through Squares(AC自动机+DP)
题目链接 难得出一个AC自动机,我还没做到这个题呢...这题思路不难想,小小的状压出一维来,不过,D和R,让我wa死了,AC自动机,还得刷啊... #include<iostream> # ...
- hdu4758 Walk Through Squares (AC自己主动机+DP)
Walk Through Squares Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others ...
- HDU 4758 Walk Through Squares( AC自动机 + 状态压缩DP )
题意:给你两个串A,B, 问一个串长为M+N且包含A和B且恰好包含M个R的字符串有多少种组合方式,所有字符串中均只含有字符L和R. dp[i][j][k][S]表示串长为i,有j个R,在自动机中的状态 ...
- hdu4758Walk Through Squares(ac自动机+dp)
链接 dp[x][y][node][sta] 表示走到在x,y位置node节点时状态为sta的方法数,因为只有2个病毒串,这时候的状态只有4种,根据可走的方向转移一下. 这题输入的是m.N,先列后行, ...
- HDU4758 Walk Through Squares(AC自动机+状压DP)
题目大概说有个n×m的格子,有两种走法,每种走法都是一个包含D或R的序列,D表示向下走R表示向右走.问从左上角走到右下角的走法有多少种走法包含那两种走法. D要走n次,R要走m次,容易想到用AC自动机 ...
- HDU 4758 Walk Through Squares (2013南京网络赛1011题,AC自动机+DP)
Walk Through Squares Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Oth ...
- HDU3341 Lost's revenge(AC自动机&&dp)
一看到ACGT就会想起AC自动机上的dp,这种奇怪的联想可能是源于某道叫DNA什么的题的. 题意,给你很多个长度不大于10的小串,小串最多有50个,然后有一个长度<40的串,然后让你将这个这个长 ...
- hdu4758 Walk Through Squares
地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=4758 题目: Walk Through Squares Time Limit: 4000/20 ...
- POJ1625 Censored!(AC自动机+DP)
题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...
随机推荐
- (三)Qt语言国际化
Vs 2010+ Qt5 实现语言国际化 创建一个工程,cpp代码如下: 1.创建工程 #include "languageinternationalized.h" #includ ...
- 安装apk文件报waiting for device 时解决办法
C:\Users\root>adb install d:\rry_0514.apkerror: more than one device and emulator- waiting for de ...
- Java 多线程的基本概念
一.线程介绍 多线程同时运行时,单CPU系统实际上是分给每个线程固定的时间片,用这种方式使得线程“看起来像是并行的”.在多CPU系统中,每个CPU可以单独运行一个线程,实现真正意义上的并行,但是如果线 ...
- C# 编写Window服务基础(一)
一.Windows服务介绍: Windows服务以前被称作NT服务,是一些运行在Windows NT.Windows 2000和Windows XP等操作系统下用户环境以外的程序.在以前,编写Wind ...
- 基于php下载文件的详解
本篇文章是对php下载文件进行了详细的分析介绍,需要的朋友参考下 php下载文件,比如txt文件. 出现的效果就是,弹出浏览器自带的下载框,出现另存为操作.有时候会出现内存溢出和超时的现象. 超时的话 ...
- java 语法糖
package syntax.autoCase; import java.util.Arrays; import java.util.List; public class autoCase { pub ...
- 修改UI中的值,无反应解决办法
var targetObj = $("<input name='mydate' class='easyui-datebox'>").appendTo("#id ...
- 感知器算法PLA
for batch&supervised binary classfication,g≈f <=> Eout(g)≥0 achieved through Eout(g)≈Ein(g ...
- CentOS 6.4 安装搭建 Scrapy 0.22 环境
一.安装Python2.7.6 更新CentOS lib库文件 yum -y update 安装开发工具包 yum groupinstall -y development 安装扩展包 yum inst ...
- WPF:实现主应用程序单一实例运行方式总结
本文介绍常见的实现主应用程序单一实例运行的几种方式. 方式一: public partial class App : Application { protected override void ...