bzoj1566[noi2009]管道取珠

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

posted @ 2016-07-09 22:32  YuanZiming  阅读(498)  评论(0编辑  收藏  举报