POJ 1189

教訓很多也收穫不少的一道題

首先是DP狀態的定義,開始一直不知道怎麼下手寫,後來覺得這個定義比較合適\(dp(i, j)\)定義爲當前假設第i行全是沒拔掉釘子,落在第i行第j個釘子上的釘子的數量(概率分數處理會很麻煩)

然後是數學上的兩個問題:

  • 一是概率,想當然的計算從頂向下方法數,結果測試數據一直髮現不對勁,就是概率的理解出現了偏差,check別人的代碼恍然大悟後利用模擬的思路,假設頂上有\(1<<n\)落下來這樣模擬。反思計算方法數從而求得概率,應該是相關的條件概率在其中出現了問題,導致計算方法數是錯誤的想法
  • 二是gcd,簡單複習了下

此外,代碼中最後循環求和實際測試比直接複製(1<<n)快就比較玄學...

中間WA了三次,主要問題是兩處,數據範圍沒有仔細斟酌,應該使用long long,另一處則是對於0的特殊處理

#include <iostream>
#include <algorithm>
#include <queue>
#include <string>
#include <vector>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <string>
#include <stack>
#include <map>
#include <set>
using namespace std;

typedef unsigned long long LL;
const int maxn= 55;

char bd[maxn][maxn];
LL dv[maxn][maxn];

inline LL GCD(LL q, LL r)
{
	return 0== r ? q : GCD(r, q%r);
}

int main(int argc, char const *argv[])
{
	int n, m;
	while (~scanf("%d %d", &n, &m)){
		for (int i= 1; i<= n; ++i){
			for (int j= 1; j<= i; ++j){
				scanf(" %c", bd[i]+j);
			}
		}

		dv[1][1]= (((LL)1)<<n);
		++n;
		for (int i= 2; i<= n; ++i){
			for (int j= 1; j<= i; ++j){
				dv[i][j]= 0;
				if (j!= i && '*'== bd[i-1][j]){
					dv[i][j]+= (dv[i-1][j])>>1;
				}
				if (j> 1){
					if ('*'== bd[i-1][j-1]){
						dv[i][j]+= (dv[i-1][j-1])>>1;
					}
					if ('.'== bd[i-2][j-1]){
						dv[i][j]+= dv[i-2][j-1];
					}
				}
			}
		}
		LL sum= 0, ans= dv[n][m+1], gcd;
		for (int i= 1; i<= n; ++i){
			sum+= dv[n][i];
		}
		gcd= GCD(sum, ans);
		sum/= gcd;
		ans/= gcd;

		if (ans){
			printf("%llu/%llu\n", ans, sum);
		}
		else{
			printf("0/1\n");
		}
	}

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