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
Author: CHEN, Zemin
Source: ZOJ Monthly, June 2014
题目大意:
给你两个长度为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:一开始老是想着怎么从之前的状态推过来,然后怎么写也写不出来,反正就是觉得蛮复杂的,可能是我太渣的缘故,反正换成从当前状态推之后的状态就容易多了,有兴趣的筒子可以尝试从之前的状态推过来,反正我是弃疗了。。
更加可悲的是取模写错导致蛙了几发,以前遇到的都是1e9 + 7的,这次直接脑不带的就这么取了。。没治了没治了
//ZOJ 3791 An Easy Game
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define clear(A, X, SIZE) memset(A, X, sizeof(A[0]) * (SIZE))
#define copy(A, B) memcpy(A, B, sizeof A)
#define min(A, B) ((A) < (B) ? (A) : (B))
#define max(A, B) ((A) > (B) ? (A) : (B))
typedef long long ll;
const int maxE = 1000000;
const int maxN = 105;
const int oo = 0x3f3f3f3f;
const int mod = 1e9 + 9;
ll C[maxN][maxN], dp[maxN][maxN];
char s1[maxN], s2[maxN];
int n, m, k;
void fun(){
for(int i = 0; i < maxN; ++i) C[i][0] = 1;
for(int i = 1; i < maxN; ++i){
for(int j = 1; j <= i; ++j){
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
}
}
void work(){
int dif = 0;
scanf("%s%s", s1, s2);
for(int i = 0; i < n; ++i) if(s1[i] != s2[i]) ++dif;
memset(dp, 0, sizeof dp);
dp[0][dif] = 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] % mod + C[j][i2] * C[n - j][m - i2] % mod * dp[i][j] % mod) % mod;
}
}
}
printf("%lld\n", dp[k][0]);
}
int main(){
fun();
while(~scanf("%d%d%d", &n, &k, &m)) work();
return 0;
}