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

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

相关文章

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

使用C#代码计算数学表达式实例

《使用C#代码计算数学表达式实例》这段文字主要讲述了如何使用C#语言来计算数学表达式,该程序通过使用Dictionary保存变量,定义了运算符优先级,并实现了EvaluateExpression方法来... 目录C#代码计算数学表达式该方法很长,因此我将分段描述下面的代码片段显示了下一步以下代码显示该方法如

VUE动态绑定class类的三种常用方式及适用场景详解

《VUE动态绑定class类的三种常用方式及适用场景详解》文章介绍了在实际开发中动态绑定class的三种常见情况及其解决方案,包括根据不同的返回值渲染不同的class样式、给模块添加基础样式以及根据设... 目录前言1.动态选择class样式(对象添加:情景一)2.动态添加一个class样式(字符串添加:情

SpringCloud配置动态更新原理解析

《SpringCloud配置动态更新原理解析》在微服务架构的浩瀚星海中,服务配置的动态更新如同魔法一般,能够让应用在不重启的情况下,实时响应配置的变更,SpringCloud作为微服务架构中的佼佼者,... 目录一、SpringBoot、Cloud配置的读取二、SpringCloud配置动态刷新三、更新@R

如何用Python绘制简易动态圣诞树

《如何用Python绘制简易动态圣诞树》这篇文章主要给大家介绍了关于如何用Python绘制简易动态圣诞树,文中讲解了如何通过编写代码来实现特定的效果,包括代码的编写技巧和效果的展示,需要的朋友可以参考... 目录代码:效果:总结 代码:import randomimport timefrom math

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�