BZOJ NOI 1999 釘子和小球 動態規劃+分數類
阿新 • • 發佈:2017-07-24
getc namespace += tchar std 有趣的 題目 小數 content
題目大意:不太好描寫敘述,自己看吧。。
思路:首先從最上面的點開始考慮。由於球一定是從最上面開始往下掉,所以球經過最上面的點的概率是1,然後他會有1/2的幾率向左,1/2的幾率向右,也就是以下的兩個點均分上面點的幾率。
當然這是全部的點都存在的情況。假設有哪裏的點不存在了,那麽求落到這個點的幾率不變,然後它的全部幾率都會加在在它以下兩行且在正下方的點。
依照這樣寫dp方程。顯然是不難的。之後就是惡心的輸出了。兩個方案,1.遇到小數就*2,保證它是整數。可是最高有50層。就要考慮一下2^50這麽大,加上一些復雜的情況,非常可能爆掉__int64,舍棄這樣的方法。2.就是寫一個分數類。
。這玩應還是第一次寫,挺有趣的。。
CODE:
#include <cstdio> #include <iomanip> #include <cstring> #include <iostream> #include <algorithm> #define MAX 100 using namespace std; long long Gcd(long long x,long long y) {return y ? Gcd(y,x % y):x;} struct Fraction{ long long up; long long down; Fraction(long long _ = 0,long long __ = 1):up(_),down(__) {} void Reduction() { long long gcd = Gcd(up,down); up /= gcd; down /= gcd; } Fraction operator +(const Fraction &a)const { Fraction re; long long gcd = Gcd(down,a.down); re.down = a.down / gcd * down; re.up = (up * a.down + a.up * down) / gcd; re.Reduction(); return re; } Fraction operator +=(const Fraction &a) { *this = *this + a; return *this; } Fraction operator *(const Fraction &a)const { Fraction re(up * a.up,down * a.down); re.Reduction(); return re; } }; int cnt,ask; char map[MAX][MAX]; Fraction f[MAX][MAX]; inline char Judge(); int main() { cin >> cnt >> ask; for(int i = 1;i <= cnt; ++i) for(int j = 1;j <= i; ++j) map[i][j] = Judge(); f[1][1] = Fraction(1,1); for(int i = 1;i <= cnt; ++i) for(int j = 1;j <= cnt; ++j) { if(map[i][j] == '*') { f[i + 1][j] += f[i][j] * Fraction(1,2); f[i + 1][j + 1] += f[i][j] * Fraction(1,2); } else f[i + 2][j + 1] += f[i][j]; } printf("%lld/%lld",f[cnt + 1][ask + 1].up,f[cnt + 1][ask + 1].down); return 0; } inline char Judge() { char c; while(c = getchar()) { if(c == '*') return '*'; else if(c == '.') return '.'; } }
BZOJ NOI 1999 釘子和小球 動態規劃+分數類