思路:反状态压缩——把数据转换成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[i-1][0]*p[i]+根据不同运算符和第i位的值运算得到0的概率。
初始状态:f[0][0~1]=0或1(根据第一个数的该位来设置)
每一位为1的期望 f[n][1]
这题只要知道怎样表示状态就很简单了!!!以上是标程……
代码如下:
1 #include<iostream> 2 #include<stdio.h> 3 #include<algorithm> 4 #include<iomanip> 5 #include<cmath> 6 #include<cstring> 7 #include<vector> 8 #define ll __int64 9 #define pi acos(-1.0) 10 #define MAX 50000 11 using namespace std; 12 double dp[202][2],p[202]; 13 char str[202]; 14 int f[202]; 15 double fun1(int i,int j){//位运算结果为1的期望值 16 double ans=0.0,pp=1-p[i]; 17 int t=(f[i]>>j)&1; 18 if(str[i]=='&'&&t){ 19 ans=dp[i-1][1]*pp; 20 } 21 else if(str[i]=='|'){ 22 ans=dp[i-1][1]*pp; 23 if(t==1) 24 ans+=dp[i-1][0]*pp; 25 } 26 else if(str[i]=='^'){ 27 if(t==1) 28 ans=dp[i-1][0]*pp; 29 else ans=dp[i-1][1]*pp; 30 } 31 return ans; 32 } 33 double fun0(int i,int j){//位运算结果为0的期望值 34 double ans=0.0,pp=1-p[i]; 35 int t=(f[i]>>j)&1; 36 if(str[i]=='&'){ 37 if(t==1) 38 ans=dp[i-1][0]*pp; 39 else ans=(dp[i-1][0]+dp[i-1][1])*pp; 40 } 41 else if(str[i]=='|'&&t==0) 42 ans=dp[i-1][0]*pp; 43 else if(str[i]=='^'){ 44 if(t==1) ans=dp[i-1][1]*pp; 45 else ans=dp[i-1][0]*pp; 46 } 47 return ans; 48 } 49 int main(){ 50 int c,n,i,j,k=0; 51 double ans; 52 while(scanf("%d",&n)!=EOF){ 53 for(i=0;i<=n;i++) scanf("%d",&f[i]); 54 for(i=1;i<=n;i++) scanf("%s",&str[i]); 55 for(i=1;i<=n;i++) scanf("%lf",&p[i]); 56 ans=0.0; 57 for(i=0;i<20;i++){ 58 c=(f[0]>>i)&1; 59 dp[0][1]=c; dp[0][0]=c^1; 60 for(j=1;j<=n;j++){ 61 dp[j][1]=dp[j-1][1]*(p[j])+fun1(j,i); 62 dp[j][0]=dp[j-1][0]*(p[j])+fun0(j,i); 63 } 64 ans+=(1<<i)*dp[n][1]; 65 } 66 printf("Case %d:\n%.6lf\n",++k,ans); 67 } 68 return 0; 69 }