ZOJ 3791 An Easy Game(DP)
One day, Edward and Flandre play a game. Flandre will show two 01-strings s1 and s2, the lengths of two strings are n. Then, Edward must move exact k steps. In each step, Edward should change exact m positions of s1. That means exact m positions of s1, '0' will be changed to '1' and '1' will be changed to '0'.
The problem comes, how many different ways can Edward change s1 to s2 after k steps? Please calculate the number of the ways mod 1000000009.
Input
Input will consist of multiple test cases and each case will consist of three lines. The first line of each case consist of three integers n (1 ≤ n ≤ 100), k (0 ≤ k ≤ 100), m (0 ≤ m ≤ n). The second line of each case is a 01-string s1. The third line of each case is a 01-string s2.
Output
For each test case, you should output a line consist of the result.
Sample Input
3 2 1 100 001
Sample Output
2
Hint
100->101->001 100->000->001
转自:http://blog.csdn.net/u013368721/article/details/28196915
题目大意:
给你两个长度为n的01串,第一个为起始串,另一个为目标串。给你k次操作,每次选择起始串的m个不同的位置取反(0变1,1变0),问k次操作以后有多少种方案能使得起始串变成目标串。
题目分析:
其实这个串上1和0的分布无所谓的,只要看起始串和目标串在没有任何操作前有多少位是不同的就行。
设dp[i][j]表示第i次操作起始串与目标串还有j个位置不匹配。
那么状态转移方程为dp[i+1][j + m - 2 * i2] = (dp[i+1][j + m - 2 * i2] % mod + C[j][i2] * C[n - j][m - i2] % mod * dp[i][j] % mod)%mod。
其中C[j][i2] * C[n - j][m - i2]表示从从匹配的位置中选了i2个,不匹配的位置中选了m - i2个的组合数,dp[i + 1][j + m - 2 * i2]就是这次操作以后与目标
串的不匹配的数目变为了j + m - 2 * i2个。
PS:一开始老是想着怎么从之前的状态推过来,然后怎么写也写不出来,反正就是觉得蛮复杂的,可能是我太渣的缘故,反正换成从当前状态推之后的状态就容易多了,有兴趣的
筒子可以尝试从之前的状态推过来,反正我是弃疗了。。
代码:
View Code#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 105;
const int mod = 1e9 + 9;
LL C[N][N],dp[N][N];//dp[i][j]表示第i次操作起始串与目标串还有j个位置不匹配
char s1[N],s2[N];
int n,k,m;
void fun()
{
for(int i = 0; i < N; ++i) C[i][0] = 1;
for(int i = 1; i < N; ++i)
{
for(int j = 1; j <= i; ++j)
{
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
}
void work()
{
int cnt = 0;
scanf("%s%s",s1,s2);
for(int i=0; i<n; i++)
{
if(s1[i] != s2[i])
cnt++;
}
memset(dp,0,sizeof(dp));
dp[0][cnt] = 1;
for(int i=0; i<k; i++)//往后推导
for(int j=0; j<=n; j++)
for(int i2=0; i2<=m; i2++)
{
if(j + m - 2 * i2 < 0)break;
if(j + m - 2 * i2 > n)continue;
dp[i+1][j+m-2*i2] = (dp[i+1][j+m-2*i2] + C[j][i2]*C[n-j][m-i2] % mod * dp[i][j]%mod)%mod;//小心乘法溢出
//printf("dp[%d][%d]=%d\n",i+1,j+m-2*i2,dp[i+1][j+m-2*i2]);
}
printf("%lld\n",dp[k][0]);
}
int main()
{
fun();
//freopen("in.txt","r",stdin);
while(~scanf("%d%d%d",&n,&k,&m))
{
work();
}
return 0;
}