atcoderI - Coins ( 概率DP)
I - Coins
Time Limit: 2 sec / Memory Limit: 1024 MB
Score : 100100 points
Problem Statement
Let NN be a positive odd number.
There are NN coins, numbered 1,2,…,N1,2,…,N. For each ii (1≤i≤N1≤i≤N), when Coin ii is tossed, it comes up heads with probability pipi and tails with probability
Taro has tossed all the NN coins. Find the probability of having more heads than tails.
Constraints
- NN is an odd number.
- 1≤N≤29991≤N≤2999
- pipi is a real number and has two decimal places.
- 0<pi<10<pi<1
Input
Input is given from Standard Input in the following format:
NN p1p1 p2p2 …… pNpN
Output
Print the probability of having more heads than tails. The output is considered correct when the absolute error is not greater than 10−910−9.
Sample Input 1 Copy
Copy3 0.30 0.60 0.80
Sample Output 1 Copy
Copy0.612
The probability of each case where we have more heads than tails is as follows:
- The probability of having (Coin1,Coin2,Coin3)=(Head,Head,Head)(Coin1,Coin2,Coin3)=(Head,Head,Head) is 0.3×0.6×0.8=0.1440.3×0.6×0.8=0.144;
- The probability of having (Coin1,Coin2,Coin3)=(Tail,Head,Head)(Coin1,Coin2,Coin3)=(Tail,Head,Head) is 0.7×0.6×0.8=0.3360.7×0.6×0.8=0.336;
- The probability of having (Coin1,Coin2,Coin3)=(Head,Tail,Head)(Coin1,Coin2,Coin3)=(Head,Tail,Head) is 0.3×0.4×0.8=0.0960.3×0.4×0.8=0.096;
- The probability of having (Coin1,Coin2,Coin3)=(Head,Head,Tail)(Coin1,Coin2,Coin3)=(Head,Head,Tail) is 0.3×0.6×0.2=0.0360.3×0.6×0.2=0.036.
Thus, the probability of having more heads than tails is 0.144+0.336+0.096+0.036=0.6120.144+0.336+0.096+0.036=0.612.
Sample Input 2 Copy
Copy1 0.50
Sample Output 2 Copy
Copy0.5
Outputs such as 0.500
, 0.500000001
and 0.499999999
are also considered correct.
Sample Input 3 Copy
Copy5 0.42 0.01 0.42 0.99 0.42
Sample Output 3 Copy
Copy0.3821815872
double p[maxn];
double dp[3050][3050];
int n;
題意:給N個硬幣,每一個硬幣扔向空中落地是正面朝上的概率是p[i] ,讓求扔了N個硬幣,正面的數量大於背面數量的概率。
很裸的概率DP,我們思考一下狀態和轉移方程。
我們這樣定義狀態,定義dp[i][j] 為到第i個硬幣時有j個是正面的概率。那麽所求答案為sum{ dp[n][i] || (n+1)/2<=i<=n}
題目說了n為odd,
那麽狀態轉移即為: dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1.0-p[i]);
意思為,到了第i個硬幣時,j個正面朝上的狀態可以由以下兩個狀態轉移過來:
1、第i-1個硬幣的時候,有j-1個正面朝上的,第i個硬幣也正面朝上。
2、第i-1個硬幣的時候,有j個正面朝上的,第i個硬幣反面朝上。
然後初始狀態定義
dp[1][1]=p[1];
dp[1][0]=1.0000000-p[1];
註意處理下邊界情況就好了。
細節見AC代碼:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), ‘\0‘, sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) using namespace std; typedef long long ll; inline void getInt(int* p); const int maxn=1000010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ double p[maxn]; double dp[3050][3050]; int n; int main() { gg(n); repd(i,1,n) { scanf("%lf",&p[i]); } dp[1][1]=p[1]; dp[1][0]=1.0000000-p[1]; repd(i,2,n) { for(int j=0;j<=i;j++) { if(j==0) { dp[i][j]=dp[i-1][j]*(1.00000-p[i]); continue; } dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1.0000-p[i]); // dp[i][j-1]=dp[i-1][j-1]*(1.000000-p[i]); } } double ans=0.0000000000000000000; for(int i=(n+1)/2;i<=n;i++) { ans+=dp[n][i]; } printf("%.10lf\n", ans); return 0; } inline void getInt(int* p) { char ch; do { ch = getchar(); } while (ch == ‘ ‘ || ch == ‘\n‘); if (ch == ‘-‘) { *p = -(getchar() - ‘0‘); while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 - ch + ‘0‘; } } else { *p = ch - ‘0‘; while ((ch = getchar()) >= ‘0‘ && ch <= ‘9‘) { *p = *p * 10 + ch - ‘0‘; } } }
atcoderI - Coins ( 概率DP)