1. 程式人生 > 實用技巧 >Atcoder Educational DP Contest I - Coins (概率DP)

Atcoder Educational DP Contest I - Coins (概率DP)

  • 題意:有\(n\)枚硬幣,每枚硬幣拋完後向上的概率為\(p[i]\),現在求拋完後向上的硬幣個數大於向下的概率.

  • 題解:我們用二維的\(dp[i][j]\)來表示狀態,\(i\)表示當前拋的是第\(i\)個硬幣,\(j\)表示的是前\(i\)個硬幣中向上的個數,那麼狀態可以表示為,如果\(j=0\),那麼\(dp[i][j]=dp[i-1][j]*(1-p[i])\),否則,\(dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[i])\).即類似01揹包的思路,當前這個狀態我選還是不選.如果選,那麼因為是\(j\)個朝上,所以要由前一枚硬幣有\(j-1\)

    個朝上的狀態轉化而來,反之同理.

  • 程式碼:

    int n;
    double p[N];
    double dp[4000][4000];
    int main() {
        //ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
    	n=read();
    	for(int i=1;i<=n;++i){
    		scanf("%lf",&p[i]);
    	}
     
    	dp[1][0]=1-p[1];
    	dp[1][1]=p[1];
     
    	for(int i=2;i<=n;++i){
    		for(int j=0;j<=i;++j){
    			if(j==0){
    				dp[i][j]=dp[i-1][j]*(1-p[i]);
    			}
    			else{
    				dp[i][j]=dp[i-1][j-1]*p[i]+dp[i-1][j]*(1-p[i]);
    			}
    		}
    	}
    	double res=0.0000000000;
    	for(int i=(n/2)+1;i<=n;++i){
    		res+=dp[n][i];
    	}
    	printf("%.10lf",res);
     
        return 0;
    }