HDU 4649 Professor Tian (概率DP)

Professor Tian

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 870    Accepted Submission(s): 479


Problem Description
Timer took the Probability and Mathematical Statistics course in the 2012, But his bad attendance angered Professor Tian who is in charge of the course. Therefore, Professor Tian decided to let Timer face a hard probability problem, and announced that if he fail to slove the problem there would be no way for Timer to pass the final exam.
As a result , Timer passed.
Now, you, the bad guy, also angered the Professor Tian when September Ends. You have to faced the problem too. The problem comes that there is an expression and you should calculate the excepted value of it. And the operators it may contains are '&' (and),'|'(or) and '^'(xor) which are all bit operators. For example: 7&3=3, 5&2=0, 2|5=7, 4|10=14, 6^5=3, 3^4=7.
Professor Tian declares that each operator Oi with its coming number Ai+1 may disappear, and the probability that it happens is Pi (0<i<=n).
 

 

Input
The input contains several test cases. For each test case, there is a integer n (0<n<=200) in the first line.In the second line, there are n+1 integers, stand for {Ai}. The next line contains n operators ,stand for {Oi}. The forth line contains {Pi}.
Ai will be less than 220, 0<=Pi<=1.
 

 

Output
For each text case, you should print the number of text case in the first line.Then output the excepted value of the expression, round to 6 decimal places.
 

 

Sample Input
2 1 2 3 ^ ^ 0.1 0.2 2 8 9 10 ^ ^ 0.5 0.78 1 1 2 & 0.5
 

 

Sample Output
Case 1: 0.720000 Case 2: 4.940000 Case 3: 0.500000
 

 

Source
 

 

Recommend
zhuyuanchen520

題目大意

初始有一個數字A0, 然後給出A1,A2..An共n個數字,這n個數字每個數字分別有一個操作符,&,|,^

且每個數字出現的概率是pi

如果某個數字出現了,那麼就和前面的數字用它的操作符進行位運算。

問最終的期望值是多少?

 

思路

這題官方題解說是反狀態壓縮,還是第一次做這種題。

知道了怎麼表示狀態這題就覺得不難做了,賽後1A。

 

題解官方的已經很詳細了,不再累贅:

 

反狀態壓縮——把數據轉換成20位的01來進行運算

 

因爲只有20位,而且&,|,^都不會進位,那麼一位一位地看,每一位不是0就是1,

這樣求出每一位是1的概率,再乘以該位的十進制數,累加,就得到了總體的期望。

 

對於每一位,狀態轉移方程如下:

 

f[i][j]表示該位取前i個數,運算得到j(0或1)的概率是多少。

 

f[i][1]=f[i-1][1]*p[i]+根據不同運算符和第i位的值運算得到1的概率。

 

f[i][0]同理。

 

初始狀態:f[0][0~1]=0或1(根據第一個數的該位來設置)

每一位爲1的期望 f[n][1]

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;

typedef long long int64;
const int INF = 0x3f3f3f3f;
const int MAXN = 210;

int n, m;
double f[MAXN][2];
int A[MAXN];
char O[MAXN];
double p[MAXN];

int main(){

    char op[10];
    int cas = 1;
    while(~scanf("%d", &n)){
        
        for(int i=0; i<=n; ++i)
            scanf("%d", &A[i]);

        for(int i=1; i<=n; ++i){
            scanf("%s", op);
            O[i] = op[0];
        }

        for(int i=1; i<=n; ++i)
            scanf("%lf", &p[i]); 

        for(int i=0; i<20; ++i)
            f[0][0] = (A[i]>>i)&1;

        double ans = 0;
        for(int i=0; i<20; ++i){
            f[0][1] = (A[0]>>i)&1;
            f[0][0] = !f[0][1];

            for(int j=1; j<=n; ++j){

                // 第j個數字不出現,0和1的概率
                f[j][0] = f[j-1][0] * p[j];
                f[j][1] = f[j-1][1] * p[j];


                // 加上出現第j個數字,0和1的概率
                if(O[j] == '^'){
                    if( (A[j]>>i) & 1 ){
                        f[j][0] += f[j-1][1]*(1-p[j]);
                        f[j][1] += f[j-1][0]*(1-p[j]);
                    } else{
                        f[j][0] += f[j-1][0]*(1-p[j]);
                        f[j][1] += f[j-1][1]*(1-p[j]);
                    }

                } else if(O[j] == '&'){
                    if( (A[j]>>i) & 1 ){
                        f[j][0] += f[j-1][0]*(1-p[j]);
                        f[j][1] += f[j-1][1]*(1-p[j]);
                    } else{
                        f[j][0] += (f[j-1][0] + f[j-1][1]) * (1-p[j]);
                       // f[j][1]: 如果用了第j個數,這裏不能出現1
                    }
                } else if(O[j] == '|'){
                    if( (A[j]>>i) & 1){
                       // f[j][0]: 不能出現這種情況
                        f[j][1] += (f[j-1][0] + f[j-1][1]) * (1-p[j]);
                    } else{
                        f[j][0] += f[j-1][0] * (1-p[j]); 
                        f[j][1] += f[j-1][1] * (1-p[j]);
                    }
                }
            }
            ans = ans + f[n][1] * (1<<i);
        }

        printf("Case %d:\n%.6f\n", cas++, ans);

    }
    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章