北京大学程序设计实习2017期末考试 5:表达式的期望值

题目链接

AC代码

#include <iostream>
#include <cstring>
#include <iomanip>

using namespace std;

inline double fuzzy_logic(double lhs, char op, int rhs) {
    switch (op) {
        case '^':
            return rhs ? 1 - lhs : lhs;
        case '|':
            return rhs ? 1 : lhs;
        case '&':
            return rhs ? lhs : 0;
        default:
            return 0;
    }
}

int arr[210];
char ops[210];
double prob[210];

int main() {
    int n, n_cases = 0;
    while (cin >> n) {
        ++n;
        double result = 0;
        int digit = 0;
        for (int i = 0; i < n; ++i)
            cin >> arr[i];
        for (int i = 1; i < n; ++i)
            cin >> ops[i];
        for (int i = 1; i < n; ++i)
            cin >> prob[i];
        for (int i = 0; i < 21; ++i) {
            double E = (double)((arr[0] >> i) & 1);
            for (int j = 1; j < n; ++j)
                E = prob[j] * E + (1 - prob[j]) * fuzzy_logic(E, ops[j], (arr[j] >> i) & 1);
            result += E * (double)(1 << digit);
            ++digit;
        }
        cout << "Case " << ++n_cases << ":" << endl << setiosflags(ios::fixed) << setprecision(6) << result << endl;
    }
}

解题思路

这道题笔者去年想了很久才也没有想出怎么解,也因为题目形式过于不按套路,当年北京大学程序设计实习期末考试中也仅有不足20人解出此题。但事实上,这道题目的设计非常漂亮,创造性地融合了动态规划和位运算,并且事实上也不是十分困难。

求离散随机变量的期望很自然的想法就是把分布列求出来,然后 E ( x ) = ∑ x ∈ Ω x ⋅ p ( x ) E(x) = \sum_{x \in \Omega} x\cdot p(x) E(x)=xΩxp(x)暴力求解。然鹅,对于这个问题,所有的可能的值有 2 n 2^n 2n种,而 n n n的范围是2~200,所以该方法是不可取的。

按位与、按位或、按位异或的位间独立性

这是这道题最为巧妙的地方——题目设计中涉及的3个符号:&|^都有一个共同的特点,就是都是位间独立的,更具体地讲,a ^ b的第 k k k位仅与ab的第 k k k位有关。这使我们可以把这个问题拆解成更为精细的子问题:对 [ 0 , 20 ) [0, 20) [0,20)内的每个 i i i,求20个整数第 i i i X i X_i Xi的期望( X i X_i Xi只可能为0或1,故这个期望是一个 [ 0 , 1 ] [0, 1] [0,1]之间的实数。那么最后求得的期望就是:
E [ X ] = E [ ∑ i = 0 20 2 i X i ] = ∑ i = 0 20 2 i E [ X i ] E[X] = E[\sum_{i = 0}^{20}2^i X_i] = \sum_{i = 0}^{20}2^i E[X_i] E[X]=E[i=0202iXi]=i=0202iE[Xi]

这个求和当然是很简单的。

动态规划

现在的事情就是对这样一个问题设计动归:
一个0, 1序列, a 0 , a 1 , ⋯ &ThinSpace; , a n a_0, a_1, \cdots, a_n a0,a1,,an,除 a 0 a_0 a0外每个 a i a_i ai对应一个按位运算符 o i o_i oi,它有 p i p_i pi的概率消失

如果动归子问题设计为:求前 a 0 , a 1 , ⋯ a k a_0, a_1, \cdots a_k a0,a1,ak(即前 k + 1 k+1 k+1 a i a_i ai)经过可能消失的运算后所得结果(这是一个随机变量,后记为 ξ i \xi_i ξi)的期望 x k x_k xk(即 E [ ξ i ] = x i E[\xi_i] = x_i E[ξi]=xi),那么显然 x 0 = a 0 x_0 = a_0 x0=a0 a 0 a_0 a0是固定且没有消失概率的),而 x n x_n xn则是我们想要的结果,接下来就是需要给 x k x_k xk x k + 1 x_{k+1} xk+1 ( k = 0 , ⋯ &ThinSpace; , n − 1 ) (k = 0, \cdots, n-1) (k=0,,n1)设计递推公式了,这里就是这个问题的巧妙之处叻

0-1分布的逻辑运算

既然已经将问题转化为对一串0, 1序列进行期望求解,问题便突然简单了起来:如果一个分布是0, 1二值分布,那它的期望不就是为1的概率嘛?所以, x k x_k xk也是 ξ k = 1 \xi_k = 1 ξk=1的概率,那么第 k + 1 k + 1 k+1位显然分2种情况:

  1. o k + 1 a k + 1 o_{k + 1} a_{k + 1} ok+1ak+1消失了,这件事发生的概率为 p k + 1 p_{k + 1} pk+1,在该条件 ξ k + 1 \xi_{k + 1} ξk+1的期望仍为 x k x_k xk
  2. o k + 1 a k + 1 o_{k + 1} a_{k + 1} ok+1ak+1没有消失,这件事发生的概率为 1 − p k + 1 1 - p_{k + 1} 1pk+1,此时 ξ k + 1 \xi_{k + 1} ξk+1的期望 ξ k o k + 1 a k + 1 \xi_{k}o_{k + 1} a_{k + 1} ξkok+1ak+1的期望——比如如果 o k + 1 o_{k + 1} ok+1^ a k + 1 a_{k + 1} ak+1是1,那么一定有
    P ( ξ k + 1 = 1 ) = P ( ξ k = 0 ) = 1 − x k P(\xi_{k + 1} = 1) = P(\xi_{k} = 0) = 1 - x_k P(ξk+1=1)=P(ξk=0)=1xk
    类似地,可以用仅与 x k + 1 x_{k + 1} xk+1有关的表达式来来表示 o k + 1 a k + 1 o_{k + 1} a_{k + 1} ok+1ak+1为“与0”、“与1”、“或0”、“或1”、“异或0”时 ξ k o k + 1 a k + 1 \xi_{k}o_{k + 1} a_{k + 1} ξkok+1ak+1的期望值(分别为 0 , x k , x k , 1 , x k 0, x_k, x_k, 1, x_k 0,xk,xk,1,xk),见AC代码中fuzzy_logic函数

第二种情形稍微复杂一些。这样,我们可以得到 x k + 1 x_{k+1} xk+1 x k x_k xk的关系式:
x k + 1 = p k + 1 x k + ( 1 − p k + 1 ) E [ ξ k + 1 o k + 1 a k + 1 ] x_{k+1} = p_{k+1}x_k + (1 - p_{k + 1}) E[\xi_{k+1}o_{k+1}a_{k+1}] xk+1=pk+1xk+(1pk+1)E[ξk+1ok+1ak+1]
其中 E [ ξ k + 1 o k + 1 a k + 1 ] E[\xi_{k+1}o_{k+1}a_{k+1}] E[ξk+1ok+1ak+1]可以用 x k x_k xk表示.

a 0 ∼ a n a_0 \sim a_{n} a0an表示输入的 n + 1 n+1 n+1个正整数的第 k k k位时, x n x_n xn就是所求结果第 k k k位的期望 E [ X k ] E[X_k] E[Xk]

其他

面对复杂的输出的时候iostream + iomanip的函数真的不如printf好用>_<

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值