您的位置:首页 > 其它

hdu4758(AC自动机+状态压缩dp)

2016-03-19 23:00 405 查看
链接:点击打开链接

题意:在一个矩阵内从左上角走到右下角,向右走得到一个R向下走得到一个D,问最后有几种走到右下角时得到的字符串包含题中给出的两个字符串

代码:

#include <queue>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MOD=1000000007;
int q[205],dp[105][105][205][4];
int fail[205],vis[205],val[205];
int str[205][30],dis[205];
int root,id;
int change(char c){
if(c=='D')return 1;
return 0;
}                                               //只有两个字符
void insert(char *s){
int u=0;
for(;*s;s++){
if(!str[u][change(*s)])
str[u][change(*s)]=root++;
u=str[u][change(*s)];
}
dis[u]|=(1<<(id-1));
id++;
}
void getfail(){
int u,v,i,l,r,temp;
l=0,r=0;
q[r++]=0;
while(l<r){
u=q[l++];
for(i=0;i<2;i++){
if(!str[u][i])
str[u][i]=str[fail[u]][i];
else
{
temp=str[u][i];
if(u)
fail[temp]=str[fail[u]][i];
dis[temp]|=dis[fail[temp]];
q[r++]=temp;
}
}
}
}
int main(){
int n,m,i,j,t,x,y,z,ans,p,q,k,h;
char s[1005];
scanf("%d",&t);
while(t--){
scanf("%d%d",&m,&n);
root=id=1;
memset(str,0,sizeof(str));
memset(val,0,sizeof(val));
memset(dis,0,sizeof(dis));
memset(fail,0,sizeof(fail));
for(i=0;i<2;i++){
scanf("%s",s);
insert(s);
}
getfail();
memset(dp,0,sizeof(dp));
dp[0][0][0][0]=1;
for(i=0;i<=n;i++)
for(j=0;j<=m;j++)                           //在ij点状态是h的数量
for(k=0;k<root;k++)
for(h=0;h<4;h++)
if(dp[i][j][k][h]){
if(i<n)
dp[i+1][j][str[k][1]][h|dis[str[k][1]]]+=dp[i][j][k][h];
dp[i+1][j][str[k][1]][h|dis[str[k][1]]]%=MOD;
if(j<m)
dp[i][j+1][str[k][0]][h|dis[str[k][0]]]+=dp[i][j][k][h];
dp[i][j+1][str[k][0]][h|dis[str[k][0]]]%=MOD;
}
ans=0;                                      //这类题还是很相似的
for(j=0;j<root;j++)
ans=(ans+dp
[m][j][3])%MOD;
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: