[dp专题000]uva 10328 Coin Toss (java 大数+dp)(Unsolved)

题目链接

题意:问长度为n,每个位置由且仅有‘H’和'T'组成的序列中,至少有连续k个‘H’出现的方案数。

思路:不会做,参考了题解 不过没有完全搞懂。

根据题解,正面考虑比较麻烦,所以反面考虑。[j]

dp[i][j]表示长度为i,前面最后连续的‘H’的个数不超过j个的方案数。

考虑转移方程为:

总的情况为:dp[i][j] = dp[i-1][j] * 2;

但是其中有多考虑的情况,就是第i位是'H',且i位之前的最后j个位置都是'H'(即从i-j位到第i-1位都是‘H’,此时第i-j-1位必然是'T')

有i个硬币时,如果i < j+1,那么它对于i-1的情况来说,最后一个硬币的位置就可以随便放了。

如果i > j + 1,dp[ i ] [ j ]  = dp [ i - 1 ] [ j ] * 2 - x(不满足条件的部分)

然后我们来考虑这个x怎么求,既然是不满足条件,那么肯定是第i的位置放了H,前面的都是H,从而这些连续的H大于j。那么就考虑dp[ i - 1 - j - 1 ](中间这 j - 1 个(kk:疑似作者笔误。应该位j个)全为H,加上第i个H,就不满足条件了),所以:

dp [ i ] [ j ] = dp [ i - 1 ] [ j ] * 2 - dp [ i - j - 2 ] [ j ](kk:仍然不是很懂这个式子...)

那么我们就差最后一个了:i == j + 1的情况了。(因为 i - j - 2 就等于 -1 了,用递推公式会RE的)

这种情况只有一种,即是全是H。

那么它就为:dp [ i ] [ j ] = dp [ i - 1 ] [ j ] * 2 - 1

最后,要用到高精度,干脆写了java

/* ***********************************************
Author :111qqz
Created Time :2016年11月11日 星期五 12时31分47秒
File Name :code/uva/10328.java
 ************************************************ */
import java.math.BigInteger;
import java.util.Scanner;

public class Main{
	public static void main(String [] args){
		Scanner cin = new Scanner(System.in);
		BigInteger[][] f = new BigInteger [110][110];
		for ( int i = 0 ; i <= 100 ; i++) f[0][i] = new BigInteger("1");
		f[1][0] = new BigInteger("1");
		for ( int i = 1 ; i <= 100 ; i++) f[1][i] = new BigInteger("2");
		for ( int i = 2 ; i <= 100 ; i++){
			for ( int j = 0 ; j <= 100;  j++){
				f[i][j] = f[i-1][j].multiply(BigInteger.valueOf(2));
				if (i==j+1)
					f[i][j] = f[i][j].add(BigInteger.valueOf(-1));
				else if (i>=j+1)
					f[i][j] = f[i][j].add(f[i-j-2][j].negate());
			}
		}
		while (cin.hasNext()){
			int n = cin.nextInt();
			int k = cin.nextInt();
			System.out.println(f[n][n].add(f[n][k-1].negate()));
		}
	}
}