1. 程式人生 > >骰子 (入門概率DP)

骰子 (入門概率DP)

【概率】骰子

時間限制: 1 Sec  記憶體限制: 128 MB
提交: 14  解決: 10
[提交] [狀態] [討論版] [命題人:admin]

題目描述

眾所周知,骰子是一個六面分別刻有一到六點的立方體,每次投擲骰子,從理論上講得到一點到六點的概率都是1/6。今有骰子一顆,連續投擲N次,問點數總和大於等於X的概率是多少?

輸入

一行兩個整數,分別表示n和x,其中1≤N≤24,0≤x<150。

輸出

一行,一個分數,要求以最簡的形式精確地表達出連續投擲N次骰子,總點數大於等於X的概率。如果是0/1就輸出0,如果是1/1,就輸出1。

樣例輸入

3 9

樣例輸出

20/27

友好的中文題面,通俗易懂的題意,初次接觸概率DP,略有不解,寫部落格以記之。
DP[i][j]表示拋i枚硬幣,點數和為j的方案數。因為每種方案都是等概率出現的,所以求得方案數之後除去總的方案數6^n就是最後的結果。方案數很容易計算,外層i從0到n-1表示拋第i枚硬幣,第二層j從0到i*6,列舉當前位置能達到的方案數,內層k從1到6,表示這次拋硬幣的結果對i+1次的影響。易得到狀態轉移:dp[i+1][j+k] += dp[i][j]

程式碼實現:

/*
Look at the star
Look at the shine for U
*/
#include<bits/stdc++.h>
#define ll unsigned long long
#define PII pair<int,int>
#define sl(x) scanf("%lld",&x)
using namespace std;
const int N = 1e6+5;
const int mod = 998244353;
const int INF = 0x3f3f3f3f;
ll inv(ll b){if(b==1)return 1; return (mod-mod/b)*inv(mod%b)%mod;}
ll fpow(ll n,ll k){ll r=1;for(;k;k>>=1){if(k&1)r=r*n%mod;n=n*n%mod;}return r;}
ll dp[1005][1005];
int main()
{
    ll n,k,i,j,m;
    cin>>n>>m;
    dp[0][0] = 1;
    for(i = 0;i < n;i++)
    {
        for(j = 0;j <= i*6;j++)
        {
            for(k = 1;k <= 6;k++) dp[i+1][j+k] += dp[i][j];
        }
    }
    ll ans = 0,temp = 1;
    for(i = m;i <= 6*n;i++) ans += dp[n][i];
    for(i = 0;i < n;i++) temp *= 6;
    if(ans%temp == 0){cout<<ans/temp<<endl;return 0;}
    ll t = __gcd(ans,temp);
    cout<<ans/t<<"/"<<temp/t<<endl;
}