UVA 10328 -—— Coin Toss【DP & 大數】

題目傳送門
在這裏插入圖片描述

題意:

給你一個硬幣,拋擲n次,問出現連續至少k個正面向上(H)的情況有多少種。

分析:

原題中問出現連續至少k個H的情況,很難下手。我們可以試着將問題轉化一下,設 dp[i][j] 表示拋擲i個硬幣出現連續至多 j 個H 的情況種數。

實際出現連續至少k個H,即出現連續k個H,k+1個H,…n個H的並集,等價於dp[n][n]-dp[n][k-1],即從連續至多n個H的情況(所有拋擲情況種類數)減去連續至多(k-1)個H的情況,這保證得到的所有情況一定至少有k個連續的H。

現在問題就變成了怎麼求dp[i][j]。

i <= j:
dp[i][j] = dp[i-1][j] × 2,即從上一階段得到的拋擲序列後面增加正和反兩種情況,如果出現連續的H個數大於j個,這種情況是非法的,但很顯然此時不會出現這種情況。當前位置隨便放。

i > j:
如果繼續用 dp[i][j] = dp[i-1][j] × 2 就不行了。因爲如果 從第 i - j 個到第 i - 1 全是H ,那麼這時候在第i個位置再加一個H,就會出現連續的H個數大於j個的非法狀態,所以我們需要減掉 從 i - j 到第 i - 1 全是H 的這種情況。那麼這種情況有多少種呢?我們考慮該狀態是如何轉移而來的。試想第 i - j - 1 個位置應該是什麼呢?很明顯只能是T。如果是H那就會出現非法狀態了。那在第 i - j - 1 之前的位置呢。無論H和T都可以,只要不出現連續的H個數大於j的非法狀態即可,這就是 dp[i-j-2][j]

那麼這樣,dp[i][j] = dp[i-1][j] × 2 - dp[i-j-2][j]

但這還是不夠的。我們之前的推導都是基於第i-j-1個位置一定存在的前提下(i>j不能保證第i-j-1個位置一定存在),那如果第i-j-1個位置不存在,第i-j-2個位置也就不存在,上述方程也就不成立了。但這種情況很好想,此時一定是i==j+1,從第1個位置到第j個位置全部都是H只有這一種情況,所以方程變成 dp[i][j]=dp[i-1][j] × 2 - 1

綜上,狀態轉移方程爲:
i<=j:dp[i][j] = dp[i-1][j] × 2;
i==j+1:dp[i][j] = dp[i-1][j] × 2 - 1;
i>j+1:dp[i][j] = dp[i-1][j] × 2 - dp[i-j-2][j]

ans=dp[n][n] - dp[n][k-1]

AC代碼:

import java.math.BigInteger;
import java.util.Scanner;

public class Main {

	public static void main(String[] args) {
		BigInteger a, b;
		BigInteger dp[][] = new BigInteger[105][105];
		//初始化
		for (int i = 0; i <= 100; i++) {
			dp[0][i] = BigInteger.valueOf(1);
			dp[i][0] = BigInteger.valueOf(1);
			dp[1][i] = BigInteger.valueOf(2);
		}
		for (int i = 1; i <= 100; i++) {
			for (int j = 1; j <= 100; j++) {
				if (i <= j)
					dp[i][j] = dp[i - 1][j].multiply(BigInteger.valueOf(2));
				else if (i == j + 1)
					dp[i][j] = dp[i - 1][j].multiply(BigInteger.valueOf(2)).subtract(BigInteger.valueOf(1));
				else
					dp[i][j] = dp[i - 1][j].multiply(BigInteger.valueOf(2)).subtract(dp[i - j - 2][j]);

			}
		}
		Scanner in = new Scanner(System.in);
		while (in.hasNext()) {
			a = BigInteger.valueOf(in.nextInt());
			b = BigInteger.valueOf(in.nextInt()).subtract(BigInteger.valueOf(1));
			System.out.println(dp[a.intValue()][a.intValue()].subtract(dp[a.intValue()][b.intValue()]));

		}

		in.close();
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章