HDU - 4758 Walk Through Squares (AC自己主动机+DP)

Description

On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special landscape.

Here is a M*N rectangle, and this one can be divided into M*N squares which are of the same size. As shown in the figure below:

01--02--03--04

|| || || ||

05--06--07--08

|| || || ||

09--10--11--12

Consequently, we have (M+1)*(N+1) nodes, which are all connected to their adjacent nodes. And actual queue phalanx will go along the edges.

The ID of the first node,the one in top-left corner,is 1. And the ID increases line by line first ,and then by column in turn ,as shown in the figure above.

For every node,there are two viable paths:

(1)go downward, indicated by ‘D‘;

(2)go right, indicated by ‘R‘;

The current mission is that, each queue phalanx has to walk from the left-top node No.1 to the right-bottom node whose id is (M+1)*(N+1).

In order to make a more aesthetic marching, each queue phalanx has to conduct two necessary actions. Let‘s define the action:

An action is started from a node to go for a specified travel mode.

So, two actions must show up in the way from 1 to (M+1)*(N+1).

For example, as to a 3*2 rectangle, figure below:

01--02--03--04

|| || || ||

05--06--07--08

|| || || ||

09--10--11--12

Assume that the two actions are (1)RRD (2)DDR

As a result , there is only one way : RRDDR. Briefly, you can not find another sequence containing these two strings at the same time.

If given the N, M and two actions, can you calculate the total ways of walking from node No.1 to the right-bottom node ?

Input

The first line contains a number T,(T is about 100, including 90 small test cases and 10 large ones) denoting the number of the test cases.

For each test cases,the first line contains two positive integers M and N(For large test cases,1<=M,N<=100, and for small ones 1<=M,N<=40). M denotes the row number and N denotes the column number.

The next two lines each contains a string which contains only ‘R‘ and ‘D‘. The length of string will not exceed 100. We ensure there are no empty strings and the two strings are different.

Output

For each test cases,print the answer MOD 1000000007 in one line.

Sample Input

 2
3 2
RRD
DDR
3 2
R
D 

Sample Output

 1
10 

题意:给你两串,求用m个R。n个D能组成多少个包括这两个串

思路:先构造一个AC自己主动机记录每一个状态包括两个串的状态,然后利用dp[i][j][k][s]表示i个R,j个D。此时AC自己主动机状态位置到k的时候,状态为s时的个数进行转移

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int mod = 1e9+7;

int dp[110][110][220][4];
int n,m;
int nxt[420][2],fail[420],end[420];
int root,cnt;

inline int change(char ch) {
	if (ch == 'R')
		return 0;
	else return 1;
}

inline int newNode() {
	for (int i = 0; i < 2; i++)
		nxt[cnt][i] = -1;
	end[cnt++] = 0;
	return cnt-1;
}

inline void init() {
	cnt = 0;
	root = newNode();
}

inline void insert(char buf[], int id) {
	int len = strlen(buf);
	int now = root;
	for (int i = 0; i < len; i++) {
		if (nxt[now][change(buf[i])] == -1)
			nxt[now][change(buf[i])] = newNode();
		now = nxt[now][change(buf[i])];
	}
	end[now] |= (1<<id);
}

inline void build() {
	queue<int> q;
	fail[root] = root;
	for (int i = 0; i < 2; i++)
		if (nxt[root][i] == -1)
			nxt[root][i] = root;
		else {
			fail[nxt[root][i]] = root;
			q.push(nxt[root][i]);
		}

	while (!q.empty()) {
		int now = q.front();
		q.pop();
		end[now] |= end[fail[now]];
		for (int i = 0; i < 2; i++)
			if (nxt[now][i] == -1)
				nxt[now][i] = nxt[fail[now]][i];
			else {
				fail[nxt[now][i]] = nxt[fail[now]][i];
				q.push(nxt[now][i]);
			}
	}
}

inline int solve() {
	dp[0][0][0][0] = 1;
	for (int x = 0; x <= n; x++)
		for (int y = 0; y <= m; y++)
			for (int i = 0; i < cnt; i++)
				for (int k = 0; k < 4; k++) {
					if (dp[x][y][i][k] == 0)
						continue;
					if (x < n) {
						int cur = nxt[i][0];
						dp[x+1][y][cur][k|end[cur]] += dp[x][y][i][k];
						dp[x+1][y][cur][k|end[cur]] %= mod;;
					}
					if (y < m) {
						int cur = nxt[i][1];
						dp[x][y+1][cur][k|end[cur]] += dp[x][y][i][k];
						dp[x][y+1][cur][k|end[cur]] %= mod;
					}
				}
	int ans = 0;
	for (int i = 0; i < cnt; i++) {
		ans += dp[n][m][i][3];
		ans %= mod;
	}
	return ans;
}

char str[210];

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		init();
		for (int i = 0; i < 2; i++) {
			scanf("%s", str);
			insert(str, i);
		}

		build();
		for (int i = 0; i <= n; i++)
			for (int j = 0; j <= m; j++)
				for (int x = 0; x < cnt; x++)
					for (int y = 0; y < 4; y++)
						dp[i][j][x][y] = 0;

		printf("%d\n", solve());
	}
	return 0;
}
时间: 2024-10-07 02:05:09

HDU - 4758 Walk Through Squares (AC自己主动机+DP)的相关文章

hdu 4758 Walk Through Squares(AC自动机+状态压缩DP)

题目链接:hdu 4758 Walk Through Squares 题意: 给你一个n*m的网格,现在你要从(1,1)走到(n,m),每次只能向右走或者向下走,走完后会形成一个包含R,D的序列,这个序列必须要包含题目给出的两个字符串,问有多少种方案. 题解: 由于要从(1,1)走到(n,m),所以这个形成的字符串包含R和D的数量是一定的. 现在考虑dp[u][i][j][k],表示包含两种串的组合状态,走了i个D,走了j个R,走到了k这个AC自动机的节点的方案数,然后dp一下就行了.复杂度为O

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

Walk Through Squares Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 944 Accepted Submission(s): 277 Problem Description On the beaming day of 60th anniversary of NJUST, as a military college whic

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

Description On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special landscape. Here is a M*N rectangle, and this one can be

HDU - 3341 Lost&amp;#39;s revenge(AC自己主动机+DP)

Description Lost and AekdyCoin are friends. They always play "number game"(A boring game based on number theory) together. We all know that AekdyCoin is the man called "nuclear weapon of FZU,descendant of Jingrun", because of his talen

HDU 2222 Keywords Search(AC自己主动机模板题)

题意:给出一个字符串和若干个模板,求出在文本串中出现的模板个数. 思路:由于有可能有反复的模板,trie树权值记录每一个模板出现的次数就可以. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map&

HDU 3247 Resource Archiver (AC自己主动机 + BFS + 状态压缩DP)

题目链接:Resource Archiver 解析:n个正常的串.m个病毒串,问包括全部正常串(可重叠)且不包括不论什么病毒串的字符串的最小长度为多少. AC自己主动机 + bfs + 状态压缩DP 用最短路预处理出状态的转移.能够优化非常多 AC代码: #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #include <queue> us

Zoj 3535 Gao the String II (AC自己主动机+dp)

题目大意: 用集合A中的串构造出一个串,使之让很多其它的setB中的串成为他的子串. 思路分析: 和 Codeforces 86C 几乎相同. 只是这里是要用A中的构造. 先用A 和 B的串构造一个自己主动机.然后对于A集合的尾结点给出一个最大后缀匹配,对于B集合的尾结点给一个权值. dp[i][j][k] 表示已经构造出来了一个长度为i的串,如今走到了自己主动机的j结点.i长度后面有k个字符是没有匹配到的. 继续在自己主动机上走进行状态转移. if(isword >= k +1 )dp [i+

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

On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special landscape. Here is a M*N rectangle, and this one can be divided into

Zoj 3545 Rescue the Rabbit(ac自己主动机+dp)

标题效果: 鉴于DNA有一个正确的顺序值.请构造一个长度I的DNA在这个序列使DNA正确的顺序值极大.它被认为是负的输出噼啪. .. IDEAS: 施工顺序是,ac己主动机上走,求最大要用到dp dp[i][j][k] 表示如今构造到了长度 i . 此时的我们把当前字符放在j节点.而且满足了k状态.k是一个10位的2进制状态压缩. 注意这道题上有坑就是一个序列可能有多个权值. 所以不能直接赋值.须要用位或. #include <cstdio> #include <iostream>