小X 離開家的時候忘記帶走了錢包,掉下的硬幣在桌子上排成了一列。正在等着哥哥回來的小Y坐在桌子旁邊,無聊地翻着桌子上的硬幣。
出於某種愛好,小Y 一次一定會同時翻轉M 枚硬幣。由於小Y 是一個愛動腦的小學生,這樣進行了若干次之後她很快想到了一個問題:有多少種方法能夠在K 次翻轉後把硬幣由原來的狀態變成現在這樣呢?
因爲小Y 是個好學的小學生,她只需要你告訴她方案數對1000000007 取模的值以方便她進行驗算就可以了。
第一行,包含三個字符N;K;M,表示硬幣的數量,翻轉的次數和每次翻轉的硬幣數量。
第2 3 行,包含N 個字母,表示硬幣在一開始的狀態和最終要變成的狀態。1 表示正面而0 表示背面。
一行包含一個整數,表示方案數對1000000007 取模的值。
3 2 1
100
001
2
樣例解釋:
100->101->001
100->000->001
• 對於30% 的數據,N <=4; 0 <= K <= 5。
• 對於60% 的數據,N <= 10。
• 對於100% 的數據,1 <= N <= 100; 0 <= K <= 100; 0 <= M <= N。
DP,動態轉移方程:
#include<iostream>
#include<cstdio>
const int Mod = 1000000007;
using namespace std;
int n, k, m, dif, fd;
long long C[101][101], f[101][101];
int a[5][101];
int main()
{
C[0][0] = 1;
scanf("%d%d%d", &n, &k, &m);
for (int i = 1; i <= n; ++i) {//求組合數
C[i][0] = 1;
for (int j = 1; j <= i; ++j)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % Mod;
}
for (int kk = 1; kk <= 2; ++kk)
for (int i = 1; i <= n; ++i)
scanf("%1d", &a[kk][i]);
for (int i = 1; i <= n; ++i)
if (a[1][i] != a[2][i]) ++dif; //算出有多少個不同
f[0][dif] = 1;
for (int i = 1; i <= k; ++i)
for (int j = 0; j <= n; ++j)
for (int kk = 0; kk <= min(m, j); ++kk)//最多看能翻多少個
{
if (n - j >= m - kk)
{
fd = j - kk + m - kk;//翻了之後有多少不同
f[i][fd] = (f[i][fd] + f[i - 1][j] * (C[j][kk] * C[n - j][m - kk] % Mod) % Mod) % Mod;
}
}
printf("%lld", f[k][0]);
}