题目链接: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(3*n*m*len(s1)*len(s2))
1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=(a);i<=(b);++i) 4 using namespace std; 5 6 const int AC_N=300+7,tyn=2; 7 int t,n,m,dp[4][111][111][212],P=1e9+7,ans; 8 char a[101],b[101]; 9 inline void up(int &a,int b){a=(a+b)%P;} 10 11 struct AC_automation{ 12 int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],tot; 13 inline int getid(char x){ 14 if(x==‘D‘)return 0; 15 return 1; 16 } 17 void nw(){cnt[++tot]=0,fail[tot]=0;mst(tr[tot],0);} 18 void init(){tot=-1,fail[0]=-1,nw();} 19 void insert(char *s,int idx,int x=0){ 20 for(int len=strlen(s),i=0,w;i<len;x=tr[x][w],i++) 21 if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot; 22 cnt[x]=1<<idx; 23 } 24 void build(int head=1,int tail=0){ 25 for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i]; 26 while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++) 27 if(tr[x][i]) 28 { 29 fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i]; 30 cnt[tr[x][i]]|=cnt[tr[fail[x]][i]]; 31 } 32 else tr[x][i]=tr[fail[x]][i]; 33 } 34 void solve() 35 { 36 mst(dp,0),dp[0][0][0][0]=1; 37 F(u,0,3)F(i,0,n)F(j,0,m)F(k,0,tot) 38 { 39 if(!dp[u][i][j][k])continue; 40 up(dp[u|cnt[tr[k][0]]][i+1][j][tr[k][0]],dp[u][i][j][k]); 41 up(dp[u|cnt[tr[k][1]]][i][j+1][tr[k][1]],dp[u][i][j][k]); 42 } 43 ans=0; 44 F(k,0,tot)up(ans,dp[3][n][m][k]); 45 printf("%d\n",ans); 46 } 47 }AC; 48 49 50 int main() 51 { 52 scanf("%d",&t); 53 while(t--) 54 { 55 scanf("%d%d%s%s",&m,&n,a,b); 56 AC.init(),AC.insert(a,0),AC.insert(b,1); 57 AC.build(),AC.solve(); 58 } 59 return 0; 60 }
时间: 2024-10-13 21:19:02