HDU 4649 Professor Tian(反状态压缩dp,概率)



本文出自   http://blog.csdn.net/shuangde800




题目链接点击打开链接


题目大意

初始有一个数字A0, 然后给出A1,A2..An共n个数字,这n个数字每个数字分别有一个操作符,&,|,^

且每个数字出现的概率是pi

如果某个数字出现了,那么就和前面的数字用它的操作符进行位运算。

问最终的期望值是多少?


思路

这题官方题解说是反状态压缩,还是第一次做这种题。

知道了怎么表示状态这题就觉得不难做了,赛后1A。


题解官方的已经很详细了,不再累赘:

反状态压缩——把数据转换成20位的01来进行运算

因为只有20位,而且&,|,^都不会进位,那么一位一位地看,每一位不是0就是1,这样求出每一位是1的概率,再乘以该位的十进制数,累加,就得到了总体的期望。

对于每一位,状态转移方程如下:

f[i][j]表示该位取前i个数,运算得到j(01)的概率是多少。

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

f[i][0]同理。

初始状态:f[0][0~1]=01(根据第一个数的该位来设置)

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




代码

/**==========================================
 *   This is a solution for ACM/ICPC problem
 *   
 *   @source: HDU 4649 Professor Tian
 *   @type:  dp
 *   @author: shuangde
 *   @blog: blog.csdn.net/shuangde800
 *   @email: zengshuangde@gmail.com
 *===========================================*/

#include
   
   
    
    
#include
    
    
     
     
#include
     
     
      
      
#include
      
      
       
       
#include
       
       
         #include 
         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< 
          
       
      
      
     
     
    
    
   
   

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值