[动态规划位运算]表达式的期望值

2024-06-20 13:28

本文主要是介绍[动态规划位运算]表达式的期望值,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

描述

给定如下表达式:

A0O1A1O2A2O3A3… OnAn

其中Ai(0<=i<=n)代表操作数,Oi(1<=i<=n)代表算子。有三类算子包括‘&’、‘|’和‘^’,这些算子拥有相同的计算优先级。每个算子Oi以及它后面相邻的操作数Ai,他们可能一起消失,消失的概率为Pi(注意为保证计算精度须使用double型数据)。

例如,对于样例输入中的第一组测试数据期望计算方法为:

(P1*P2)*A0+(1-P1)*(P2)*(A0O1 A1)+(P1)*(1-P2)*(A0O2A2)+(1-P1)*(1-P2)*( A0O1A1O2A2)=0.1*0.2*1+0.9*0.2*(1^2)+0.1*0.8*(1^3)+0.9*0.8*(1^2^3)=0.72

输入

输入包含若干测试样例。
对于每组测试样例,第一行为正整数n ( 0 < n <= 200 )
第二行包含n+1个正整数代表操作数集合{A}(其中Ai小于2^20),
第三行包含n个算子代表操作算子集合{O},第四行包含n个浮点数代表概率集合{P}(其中0 <= Pi <= 1)。

输出

对于每组测试样例,第一行输出测试样例序号(从1开始)。然后,输出期望值,近似到小数点后6位。

样例输入

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

样例输出

Case 1: 
0.720000 
Case 2: 
4.940000 
Case 3: 
0.500000
解题分析

首先,稍稍分析一下题目的运算的数量级,我们可以发现2^200是一个非常大的数,所以直接排除枚举法。那还有啥办法呢?我们注意到,在这里的每一个运算都是位运算,而位运算有一个很有意思的特点就是位间独立性,而且题目不是也提示了吗,每个数不超过2^20,所以我们只要考虑这20位就可以了!那么,问题就变成了一堆0,1序列了,我们不妨设每个数的二进制表示的第i位为ai,那么我们不妨先考虑一下只有0,1两个值的一个分布列,那么期望就是为1的概率。回到这个问题上来,其实我们可以考虑一下它们直接的递推关系,设Xk为到第k个数时,整个序列的期望,那么,由于结果只有0和1,为他们两个的二值分布,所以实际上Xk=表达式的值为1的概率。那么,显然有,当第k+1个数的运算符和数字都被吃掉的时候,有prob[k+1]的概率,这个时候,Xk+1的值就是Xk,第二种情况就是,运算符没有被吃掉,那么分别分为三种情况讨论,我们用一个calculate函数去表示,Xk+1=prob[k+1]*Xk+(1-prob[k+1])*Xk+1; 此处的Xk+1可以定义为calculate(E,ops[k+1],(nums[k+1]>>i)&1)。 注意,calculate函数返回的也是一个概率(或者说期望),即Xk+1。有时候最后一个数字可以决定整个表达式的值,比如肯定为1或者肯定为0这样子。最后我们把每一位乘上相应的2的某个次方相加即可。

代码实现
#include <iostream>
#include <cmath>
//#include <iomanip>
#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <list>
#include <bitset>
#include <queue>
#include <stack>
#include <cstdlib>
using namespace std;int nums[205];char ops[205];double probs[205];double calculate(double l,char op,double r){if(op=='&'){return r?l:0;}else if(op=='|'){return r?1:l;}else if(op=='^'){return r?1-l:l;}return 0;
}int main(){int n,t=0;while(scanf("%d",&n)!=EOF){t++;printf("Case %d:\n",t);double res=0;for(int i=0;i<=n;i++){scanf("%d",&nums[i]);}for(int i=1;i<=n;i++){scanf(" %c",&ops[i]);}for(int i=1;i<=n;i++){scanf("%lf",&probs[i]);}for(int i=0;i<=20;i++){double E=(double)((nums[0]>>i) & 1);for(int j=1;j<=n;j++){E=probs[j]*E+(1-probs[j])*calculate(E,ops[j],(nums[j]>>i) & 1);}res += E * (double)(1<<i);}printf("%.6lf\n",res);}return 0;
}

这个做法非常巧妙,这里也很感谢一个学长or学姐提供的原理做法,这道题还是蛮有难度的!

@

逸修竹榭

这篇关于[动态规划位运算]表达式的期望值的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1078255

相关文章

Java使用Javassist动态生成HelloWorld类

《Java使用Javassist动态生成HelloWorld类》Javassist是一个非常强大的字节码操作和定义库,它允许开发者在运行时创建新的类或者修改现有的类,本文将简单介绍如何使用Javass... 目录1. Javassist简介2. 环境准备3. 动态生成HelloWorld类3.1 创建CtC

浅谈MySQL的容量规划

《浅谈MySQL的容量规划》进行MySQL的容量规划是确保数据库能够在当前和未来的负载下顺利运行的重要步骤,容量规划包括评估当前资源使用情况、预测未来增长、调整配置和硬件资源等,感兴趣的可以了解一下... 目录一、评估当前资源使用情况1.1 磁盘空间使用1.2 内存使用1.3 CPU使用1.4 网络带宽二、

C++11右值引用与Lambda表达式的使用

《C++11右值引用与Lambda表达式的使用》C++11引入右值引用,实现移动语义提升性能,支持资源转移与完美转发;同时引入Lambda表达式,简化匿名函数定义,通过捕获列表和参数列表灵活处理变量... 目录C++11新特性右值引用和移动语义左值 / 右值常见的左值和右值移动语义移动构造函数移动复制运算符

go动态限制并发数量的实现示例

《go动态限制并发数量的实现示例》本文主要介绍了Go并发控制方法,通过带缓冲通道和第三方库实现并发数量限制,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面... 目录带有缓冲大小的通道使用第三方库其他控制并发的方法因为go从语言层面支持并发,所以面试百分百会问到

一文详解SpringBoot中控制器的动态注册与卸载

《一文详解SpringBoot中控制器的动态注册与卸载》在项目开发中,通过动态注册和卸载控制器功能,可以根据业务场景和项目需要实现功能的动态增加、删除,提高系统的灵活性和可扩展性,下面我们就来看看Sp... 目录项目结构1. 创建 Spring Boot 启动类2. 创建一个测试控制器3. 创建动态控制器注

springboot如何通过http动态操作xxl-job任务

《springboot如何通过http动态操作xxl-job任务》:本文主要介绍springboot如何通过http动态操作xxl-job任务的问题,具有很好的参考价值,希望对大家有所帮助,如有错... 目录springboot通过http动态操作xxl-job任务一、maven依赖二、配置文件三、xxl-

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

Java Lambda表达式的使用详解

《JavaLambda表达式的使用详解》:本文主要介绍JavaLambda表达式的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言二、Lambda表达式概述1. 什么是Lambda表达式?三、Lambda表达式的语法规则1. 无参数的Lambda表

MyBatis编写嵌套子查询的动态SQL实践详解

《MyBatis编写嵌套子查询的动态SQL实践详解》在Java生态中,MyBatis作为一款优秀的ORM框架,广泛应用于数据库操作,本文将深入探讨如何在MyBatis中编写嵌套子查询的动态SQL,并结... 目录一、Myhttp://www.chinasem.cnBATis动态SQL的核心优势1. 灵活性与可

C/C++中OpenCV 矩阵运算的实现

《C/C++中OpenCV矩阵运算的实现》本文主要介绍了C/C++中OpenCV矩阵运算的实现,包括基本算术运算(标量与矩阵)、矩阵乘法、转置、逆矩阵、行列式、迹、范数等操作,感兴趣的可以了解一下... 目录矩阵的创建与初始化创建矩阵访问矩阵元素基本的算术运算 ➕➖✖️➗矩阵与标量运算矩阵与矩阵运算 (逐元