【JZOJ】【DP】翻硬幣

LinkLink

JZOJJZOJ 39213921

DescriptionDescription

小X 離開家的時候忘記帶走了錢包,掉下的硬幣在桌子上排成了一列。正在等着哥哥回來的小Y坐在桌子旁邊,無聊地翻着桌子上的硬幣。
出於某種愛好,小Y 一次一定會同時翻轉M 枚硬幣。由於小Y 是一個愛動腦的小學生,這樣進行了若干次之後她很快想到了一個問題:有多少種方法能夠在K 次翻轉後把硬幣由原來的狀態變成現在這樣呢?
因爲小Y 是個好學的小學生,她只需要你告訴她方案數對1000000007 取模的值以方便她進行驗算就可以了。

InputInput

第一行,包含三個字符N;K;M,表示硬幣的數量,翻轉的次數和每次翻轉的硬幣數量。
第2 3 行,包含N 個字母,表示硬幣在一開始的狀態和最終要變成的狀態。1 表示正面而0 表示背面。

OutputOutput

一行包含一個整數,表示方案數對1000000007 取模的值。

SampleSample InputInput

3 2 1
100
001

SampleSample OutputOutput

2

HintHint

樣例解釋:
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。

TrainTrain ofof ThoughtThought

DP,動態轉移方程:
f[i][fd]=f[i][fd]+f[i1][j]C[j][kk]C[nj][mkk]f[i][fd] = f[i][fd] + f[i - 1][j] * C[j][kk] * C[n - j][m - kk]

CodeCode

#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]);
}
發佈了224 篇原創文章 · 獲贊 35 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章