这道题当时做的时候觉得是数论题,包含两个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的更多相关文章

  1. HDU 4758 Walk Through Squares(AC自动机+DP)

    题目链接 难得出一个AC自动机,我还没做到这个题呢...这题思路不难想,小小的状压出一维来,不过,D和R,让我wa死了,AC自动机,还得刷啊... #include<iostream> # ...

  2. hdu4758 Walk Through Squares (AC自己主动机+DP)

    Walk Through Squares Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others ...

  3. 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,在自动机中的状态 ...

  4. hdu4758Walk Through Squares(ac自动机+dp)

    链接 dp[x][y][node][sta] 表示走到在x,y位置node节点时状态为sta的方法数,因为只有2个病毒串,这时候的状态只有4种,根据可走的方向转移一下. 这题输入的是m.N,先列后行, ...

  5. HDU4758 Walk Through Squares(AC自动机+状压DP)

    题目大概说有个n×m的格子,有两种走法,每种走法都是一个包含D或R的序列,D表示向下走R表示向右走.问从左上角走到右下角的走法有多少种走法包含那两种走法. D要走n次,R要走m次,容易想到用AC自动机 ...

  6. 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 ...

  7. HDU3341 Lost's revenge(AC自动机&&dp)

    一看到ACGT就会想起AC自动机上的dp,这种奇怪的联想可能是源于某道叫DNA什么的题的. 题意,给你很多个长度不大于10的小串,小串最多有50个,然后有一个长度<40的串,然后让你将这个这个长 ...

  8. hdu4758 Walk Through Squares

    地址:http://acm.split.hdu.edu.cn/showproblem.php?pid=4758 题目: Walk Through Squares Time Limit: 4000/20 ...

  9. POJ1625 Censored!(AC自动机+DP)

    题目问长度m不包含一些不文明单词的字符串有多少个. 依然是水水的AC自动机+DP..做完后发现居然和POJ2778是一道题,回过头来看都水水的... dp[i][j]表示长度i(在自动机转移i步)且后 ...

随机推荐

  1. Codevs

     时间限制: 1 s  空间限制: 128000 KB  题目等级 : 白银 Silver 题解       题目描述 Description 给出n和n个整数,希望你从小到大给他们排序 输入描述 I ...

  2. Template_16_模板与继承

    1,名称模板参数template <typename PolicySetter1 = DefaultPolicy1,    typename PolicySetter2 = DefaultPol ...

  3. TextEdit验证

    using System;using System.Collections.Generic;using System.ComponentModel;using System.Drawing;using ...

  4. 字符串转成int数组

    package lianxi; import java.awt.image.ConvolveOp; public class ZhengshuShuzu { public static void ma ...

  5. hadoop架构

    HADOOP中可以分为两个大的模块,存储模块和计算模块.HDFS作为存储模块,JobTracker,TaskTracker构成计算模块.   1.HADOOP的文件是以HDFS格式存储的   HDFS ...

  6. maven 相关

    maven相关 一 windows安装配置maven: 1. 官网下载最新版本maven,发布日志时为: maven3.2.1 2.解压maven到相应的目录:配置环境变量: MAVEN_HOME:D ...

  7. iOS实现图片的缩放和居中显示

    直接上代码 // // MoveScaleImageController.h // MoveScaleImage // // Created by on 12-4-24. // Copyright ( ...

  8. IOC学习

    控制反转(Inversion of Control,英文缩写为IoC)是一个重要的面向对象编程的法则来削减计算机程序的耦合问题,也是轻量级的Spring框架的核心. 控制反转一般分为两种类型,依赖注入 ...

  9. IE下同样的$.ajax()被调用两次,只能执行一次(第一次)

    今天发现了这个问题,仅限于IE下所有浏览器包括Edge 百度了一下原来问题就在这句话:如果第二次请求与第一次请求完全相同,会直接从缓存获取. 那么就在请求时让URL变得不一样吧 $.ajax({ ty ...

  10. 关于字符串 “*****AB**C*D*****” 中前缀、后缀和中间 '*' 的处理

    一.删除前缀 '*' #include<iostream> #include<cstdio> using namespace std; //主函数 int main() { ] ...