bzoj1566[noi2009]管道取珠
题意:
有个装置,左侧有上下两条管道分别有n个和m个不同颜色的两种球,右侧一条空管道。每次可以选左侧的一条管道将最右侧的球推到右侧管道,经过n+m次操作,右侧管道从右到左形成一个输出序列。求不同种类的输出序列的产生方式数的平方之和。n,m≤500
题解:
将题目转化成两个人同时取,取出来的序列相同的可能性有多少种。于是做dp。方程见代码。f[i][j][k][l]表示第一个人取了i个Aj个B第二个人取了k个Al个B。
代码:
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #define inc(i,j,k) for(int i=j;i<=k;i++) 5 #define dec(i,j,k) for(int i=j;i>=k;i--) 6 #define mod 1024523 7 using namespace std; 8 9 int f1[600][600],f2[600][600],n,m; char s1[600],s2[600]; 10 int main(){ 11 scanf("%d%d",&n,&m); scanf("%s%s",s1,s2); 12 inc(i,0,n)inc(j,0,n)f1[i][j]=1; 13 inc(i,1,n+m){ 14 memset(f2,0,sizeof(f2)); 15 dec(j,min(i,n),0)dec(k,min(i,n),0){ 16 int a1=i-j,a2=i-k; if(a1>m||a2>m)continue; 17 if(j!=0&&k!=0&&s1[j-1]==s1[k-1])f2[j][k]=(f2[j][k]+f1[j-1][k-1])%mod; 18 if(j!=0&&a2!=0&&s1[j-1]==s2[a2-1])f2[j][k]=(f2[j][k]+f1[j-1][k])%mod; 19 if(k!=0&&a1!=0&&s2[a1-1]==s1[k-1])f2[j][k]=(f2[j][k]+f1[j][k-1])%mod; 20 if(a1!=0&&a2!=0&&s2[a1-1]==s2[a2-1])f2[j][k]=(f2[j][k]+f1[j][k])%mod; 21 } 22 swap(f1,f2); 23 } 24 int ans=0; inc(i,1,n)inc(j,1,n)ans=(ans+f1[i][j])%mod; printf("%d",ans); 25 }
20160320