https://www.luogu.com.cn/problem/AT_dp_i
第1題 拋硬幣 檢視測評資料資訊
有n個質地不均勻的硬幣,拋第i枚硬幣器正面朝上的機率是p[i],反面朝上的機率是1-p[i],扔完n個硬幣後,求正面朝上的個數大於反面朝上的機率是多少。結果保留三位小數
輸入格式
第一行一個整數n,表示有n枚硬幣
第二行n個實數,表示第i個數的正面朝上的機率
1<=n<=2999,0<p[i]<1
輸出格式
一個實數
輸入/輸出例子1
輸入:
3
0.30 0.60 0.80
輸出:
0.612
輸入/輸出例子2
輸入:
1
0.50
輸出:
0.500
樣例解釋
無
看到機率,就往dp方面想
寫dp前可以先看範圍
這題O(n^2),不難想到第一維肯定是對於前i個硬幣。
狀態要轉個彎,直接求正面>反面比較難算,我們可以求出正面數量,用n-正面得出反面,就可以比較了
狀態就出來了,f[i][j]: 考慮前i個硬幣,有j個正面朝上的機率
轉移:按照第i個硬幣正反討論:
1.正: f[i-1][j-1]*p[i]
2.反: f[i-1][j]*(1-p[i])
答案:
f[n,n/2+1~n]
這題類似揹包,就是選和不選
#include <bits/stdc++.h> using namespace std; const int N=3010; int n; double a[N], f[N][N], ans=0; int main() { scanf("%d", &n); for (int i=1; i<=n; i++) scanf("%lf", &a[i]); f[0][0]=1; for (int i=1; i<=n; i++) for (int j=0; j<=i; j++) { if (j>=1) f[i][j]=f[i-1][j-1]*a[i]; f[i][j]+=f[i-1][j]*(1.0-a[i]); } /* for (int i=1; i<=n; i++) { for (int j=1; j<=i; j++) printf("%.3lf ", f[i][j]); printf("\n"); }*/ for (int i=n/2+1; i<=n; i++) ans+=f[n][i]; printf("%.3lf", ans); return 0; }