ZOJ3791 An Easy Game(DP)

给两个长n的01串s1和s2,要对s1进行k次修改,每次修改m个不同位置,问有几种方式修改成s2。

想偏了,只想到原始的01数值是不重要的,因为每个位置修改次数的奇偶性是确定的这一层。。

其实,这题只要关心从起点到终点有几个位置是不同的,一个数值足矣。

然后具体的状态就是:dp[i][j]表示,进行i次修改后有j个位置不同的方案数。

转移用我为人人,dp[i][j]通过选择修改a个位置不同、m-a个位置相同转移到dp[i+1][j-(a-(m-a))],即dp[i+1][j-(a-(m-a))]=∑C(j,a)*C(n-j,m-a)*dp[i][j]。

这题的状态的设计和转移对我来说还是挺巧的。。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 using namespace std;
 5 long long d[111][111],C[111][111];
 6 int main(){
 7     for(int i=0; i<111; ++i) C[i][0]=1;
 8     for(int i=1; i<111; ++i){
 9         for(int j=1; j<=i; ++j) C[i][j]=(C[i-1][j-1]+C[i-1][j])%1000000009;
10     }
11     char s1[111],s2[111];
12     int n,k,m;
13     while(~scanf("%d%d%d",&n,&k,&m)){
14         scanf("%s%s",s1,s2);
15         int cnt=0;
16         for(int i=0; i<n; ++i){
17             if(s1[i]!=s2[i]) ++cnt;
18         }
19         memset(d,0,sizeof(d));
20         d[0][cnt]=1;
21         for(int i=0; i<k; ++i){
22             for(int j=0; j<=n; ++j){
23                 if(d[i][j]==0) continue;
24                 for(int k=0; k<=j; ++k){
25                     if(j-(k-(m-k))<0 || n-j<0 || m-k<0) continue;
26                     d[i+1][j-(k-(m-k))]+=C[j][k]*C[n-j][m-k]%1000000009*d[i][j]%1000000009;
27                     d[i+1][j-(k-(m-k))]%=1000000009;
28                 }
29             }
30         }
31         printf("%lld\n",d[k][0]);
32     }
33     return 0;
34 } 

 

posted @ 2016-02-09 22:18  WABoss  阅读(264)  评论(0编辑  收藏  举报