题意:
在一个(n+1)*(m+1)的矩阵中从0点到(n+1)(m+1)点,每次只能向左走或者向下走,问所有走法中包含所给出的2种子串的走法有多少种。
分析:
AC自动机类的题目做多了,就能看出这类题的套路。可以根据这2个子串建立tire图然后记dp【x】【y】【t】【k】表示向左走x步右走y步到达自动机t节点时候为状态k(0<=k<4)(0-->不包含任何子串,1-->只包含第一种子串,2-->只包含第二种子串,3-->都包含)
ACcode:
#include <bits/stdc++.h>
#define mod 1000000007
using namespace std;
int N,M,loop;
char str[101];
int dp[101][101][202][4];
struct Aho{
struct state{
int next[2];
int fail,cnt;
}s[202];
queue<int>q;
int size;
void init(){
while(q.size())q.pop();
for(int i=0;i<202;++i){
memset(s[i].next,-1,sizeof(s[i].next));
s[i].fail=s[i].cnt=0;
}
size=1;
}
void insert(char *str,int t){
int now=0;
int n=strlen(str);
for(int i=0;i<n;++i){
int id=0;
if(str[i]=='D')id=1;
if(s[now].next[id]==-1)
s[now].next[id]=size++;
now=s[now].next[id];
}
s[now].cnt|=t;
}
void build(){
s[0].fail=0;
for(int i=0;i<2;++i){
if(s[0].next[i]==-1)
s[0].next[i]=0;
else {
s[s[0].next[i]].fail=0;
q.push(s[0].next[i]);
}
}
while(q.size()){
int u=q.front();
q.pop();s[u].cnt|=s[s[u].fail].cnt;
for(int i=0;i<2;++i){
if(s[u].next[i]==-1)
s[u].next[i]=s[s[u].fail].next[i];
else{
s[s[u].next[i]].fail=s[s[u].fail].next[i];
q.push(s[u].next[i]);
}
}
}
for(int i=0;i<=N;++i)
for(int j=0;j<=M;++j)
for(int t=0;t<=size;++t)
for(int k=0;k<4;++k)
dp[i][j][t][k]=0;
dp[0][0][0][0]=1;
for(int i=0;i<=N;++i)
for(int j=0;j<=M;++j)
for(int t=0;t<size;++t)
for(int k=0;k<4;++k){
if(dp[i][j][t][k]==0)continue;
if(i<N)
dp[i+1][j][s[t].next[0]][k|s[s[t].next[0]].cnt]=(dp[i+1][j][s[t].next[0]][k|s[s[t].next[0]].cnt]+dp[i][j][t][k])%mod;
if(j<M)
dp[i][j+1][s[t].next[1]][k|s[s[t].next[1]].cnt]=(dp[i][j+1][s[t].next[1]][k|s[s[t].next[1]].cnt]+dp[i][j][t][k])%mod;
}
int ans=0;
for(int i=0;i<size;++i)
ans=(ans+dp[N][M][i][3])%mod;
printf("%d\n",ans);
}
}aho;
int main(){
scanf("%d",&loop);
while(loop--){
scanf("%d%d",&N,&M);
aho.init();
scanf("%s",str);
aho.insert(str,1);
scanf("%s",str);
aho.insert(str,2);
aho.build();
}
return 0;
}
/*
10
3 3
DDR
RR
4 4
DDR
RR
5 5
DDR
RR
6 6
DDR
RR
*/