zoukankan      html  css  js  c++  java
  • D4上午

    概率和期望DP

    概率

    某个事件A发生的可能性的大小,称之为事件A的概率,记作P(A)。

    假设某事的所有可能结果有n种,每种结果都是等概率,事件A涵盖其中的m种,那么P(A)=m/n。

    例如投掷一枚骰子,点数小于3的概率为2/6=1/3。

    如果两个事件A和B所涵盖的结果没有交集,那么P(A或B发生)=P(A)+P(B)

    还是掷骰子

    P(点数小于3或点数大于4) = 2/6+2/6=2/3

    如果A和B所涵盖的结果有交集

    那么P(A或B发生)=P(A)+P(B)-P(A与B同时发生)

    P(点数小于3或点数为偶数)=2/6+3/6-1/6=2/3

    记事件B为“事件A不发生”

    那么P(A)+P(B)=1,即P(B)=1-P(A)

    P(点数不小于3)=1-2/6=2/3

    在两个互不干扰的事中,事件A在其中一件事中,事件B在另外一件事中

    那么P(A与B同时发生)=P(A)*P(B)

    掷两个骰子, P(第一个点数小于3且第二个点数为偶数)=(2/6)*(3/6)=1/6

    期望

    事件A有多种结果,记其结果的大小为x,那么x的期望值表示
    事件A的结果的平均大小,记作E(x)。

    E(x)=每种结果的大小与其概率的乘积的和。

    例如,记掷一枚骰子的点数为x

    E(x)=1(1/6)+2(1/6)+3(1/6)+4(1/6)+5(1/6)+6(1/6)=7/2

    若c为常数,那么:

    E(x+c)=E(x)+c, E(cx)=cE(x)

    把c提出来就可以证明了

    期望的线性性质

    记两个事件的结果分别为x, y

    E(x+y)=E(x)+E(y) (天天用,在任何情况下都成立)

    例如: E(语文成绩+数学成绩)=E(语文成绩)+E(数学成绩)

    若两个事件互相独立, E(xy)=E(x)E(y) (也就是说这两个事件的概率不对对方造成影响)

    E(语文成绩 * 数学成绩 )=E(语文成绩)*E(数学成绩)

    概率和期望的计算

    概率与期望的计算有一个共同的计算技巧:

    若事件所产生的所有方案都是等概率的,那么一些概率与期望即可转化为一个计数问题,算出后再除以总方案数即可。

    如求事件符合条件A的概率,则转化为对符合A的方案数的计数问题;若求方案的某种价值的期望值,则转化为所有方案的价值总和的计数问题。

    概率与期望还可以通过列方程的方法计算。

    有4张卡片,写着0, 1, 2, 3,每次抽出一张并放回,反复抽,抽出0为止。问抽取的次数的期望值。

    设抽取次数为x,则:

    x=1+x*3/4

    x=4

    bzoj1867

    有一个三角形木板, 竖直立放,上面钉着n(n+1)/2颗钉子,还有(n+1)个格子(当n=5时如图1)。每颗钉子和周围的钉子的距离都等于d,每个格子的宽度也都等于d,且除了最左端和最右端的格子外每个格子都正对着最下面一排钉子的间隙。

    让一个直径略小于d的小球中心正对着最上面的钉子在板上自由滚落,小球每碰到一个钉子都可能落向左边或右边(概率各1/2),且球的中心还会正对着下一颗将要碰上的钉子。例如图2就是小球一条可能的路径。

    我们知道小球落在第i个格子中的概率
    pi= ,其中i为格子的编号,从左至右依次为0, 1, ..., n。

    现在的问题是计算拔掉某些钉子后,小球落在编号为m的格子中的概率pm。假定最下面一排钉子不会被拔掉。例如图3是某些钉子被拔掉后小球一条可能的路径。

    題解

    比较简单的概率dp

    设f[i][j]为小球经过第i行第j列的概率。

    f[1][1]=1 (即初始状态概率为1

    此处注意f[i-1][j-1]左上方f[i-1][j]正上方(金字塔形为右上方)

    f[i][j]=f[i-1][j-1] * [(i-1, j-1)有钉子]*1/2(1/2是算期望的时候有没有钉子概率各一半)

    + f[i-1][j] * [(i-1, j)有钉子]*1/2

    + f[i-2][j-1] * [(i-2, j-1)没有钉子] ( 没有钉子是直接落下来两格 )

    至于分数输出,自定义分数数据类型并用gcd化简分数即可

    开锁魔法

    有 n 个箱子,每个箱子里有且仅有一把钥匙,每个箱子有且仅有一把钥匙可以将其打开。现在随机打开 m 个箱子,求能够将所有箱子打开的概
    率。

    100组数据, k<=n<=300。

    题目约定了每个点的入度和出度均为1,因此最终的图一定是若干个环。

    每个环都至少选择一个点即可满足要求。求概率,实际上就是求方案数,最后再除以总方案数即可。

    预处理出每个环的点数 c[i] 以及其后缀和 sum[i] 。

    设 f[i][j] 表示前 i 个环中选出 j 个点,满足最终条件每个环都选的方案数。
    初始化 f[0][0]=1 。

    枚举 i 和 前 i 个环选的点数 j 、第 i 个环选的点数 k。
    可得

    bzoj5091

    在花园中有n棵苹果树以及m条双向道路,每条道路的两端连接着两棵不同的苹果树。假设第i棵苹果树连接着di条道路。

    小Q将会按照以下方式去采摘苹果:

    1. 随机移动到一棵苹果树下,移动到第i棵苹果树下的概率为di/2m,但不在此采摘。

    1. 重复以下操作k次:等概率随机选择一条与当前苹果树相连的一条道路,

    移动到另一棵苹果树下,假设当前位于第i棵苹果树下,则他会采摘ai个苹
    果,多次经过同一棵苹果树下会重复采摘。

    请计算小Q期望摘到多少苹果。

    n, k<=100000, m<=200000

    bzoj 4832 抵制克苏恩

    你有一个英雄和若干奴隶主,对方每次攻击会从你的英雄和奴隶主中随机选一个造成一点伤害。
    奴隶主受到攻击后,体力为0则死亡,否则若场上奴隶主少于7个,则召唤一个3点血量的奴隶主。

    有T局游戏,每局给出初始奴隶主的数量(<=7)和血量(<=3),给出k,求对方攻击k次后你的英雄受到的总伤害值的期望。

    T<=100, k<=50。

    题解

    设f[i][a][b][c]表示还要进行i轮攻击,三种血量的奴隶主数量分别为abc时,接下来英雄受到的期望总伤害。

    转移只要枚举当前攻击到的是英雄还是哪种奴隶主即可。

    初始f[0][a][b][c]=0。

    要注意每次c减少的时候都要判断一下是不是要加一个奴隶主

    每次询问可以O(1)回答。

    代码吧

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cmath>
    using namespace std;
    
    int T, K, A, B, C;
    double f[53][10][10][10];
    
    int main()
    {
        // f(i,a,b,c) 表示 攻击次数还剩i次 奴隶主中血量为1的有a个 血量为2的有b个 血量为3的有c个的期望
        for (int i = 0; i < 50; ++i)
            for (int a = 0; a <= 7; ++a)
                for (int b = 0; b <= 7 - a; ++b)
                    for (int c = 0; c <= 7 - a - b; ++c)
                    {
                        int j = a + b + c;
                        double tot = 1.0 / (a + b + c + 1.0);
                        // 攻击英雄
                        f[i + 1][a][b][c] += (f[i][a][b][c] + 1.0) * tot;
                        // 攻击血量为1的奴隶主,奴隶主死亡
                        if (a)
                            f[i + 1][a][b][c] += f[i][a - 1][b][c] * (double)a * tot;
                        // 攻击血量为2的奴隶主,血量变为1,并且判断是否能召唤血量为3的奴隶主
                        if (b)
                        {
                            if (j < 7)
                                f[i + 1][a][b][c] += f[i][a + 1][b - 1][c + 1] * (double)b * tot;
                            else
                                f[i + 1][a][b][c] += f[i][a + 1][b - 1][c] * (double)b * tot;
                        }
                        // 攻击血量为3的奴隶主,血量变为2,并且判断是否能召唤血量为3的奴隶主
                        if (c)
                        {
                            if (j < 7)
                                f[i + 1][a][b][c] += f[i][a][b + 1][c] * (double)c * tot;
                            else
                                f[i + 1][a][b][c] += f[i][a][b + 1][c - 1] * (double)c * tot;
                        }
                    }
        scanf("%d", &T);
        while (T--)
        {
            scanf("%d%d%d%d", &K, &A, &B, &C);
            printf("%.2lf
    ", f[K][A][B][C]);
        }
    }
    
    

    NOIP2016 换教室

    小A的学校可以视为一个v个点的无向图,他有n门课程要按顺序上课,其中第i门课程要在节点ai进行,但还有一个备选地点bi。

    现在小A有m个申请机会,若申请第i门课,那么将有ki的概率使课程搬到bi进行。每门课最多申请一次,而且要在全部申请完成后才知道是否成功,

    m次机会不必全部用完。他如何申请才能最小化在上课地点间移动的距离的期望值。求该期望值。

    v<=300, n, m<=2000

    首先可以floyd求出任意两点间最短路径。

    可以想到一个显然的dp状态: f[i][j][0/1]表示前i个课程申请了j次,且第i个是否申请时的最小期望值。

    转移示例:

    f[i][j][0]=Max{ f[i-1][j][0]+dis(a[i-1], a[i]) , 
    
    f[i-1][j][1]+k[i-1]*dis(b[i-1], a[i])+(1-k[i-1])*dis(a[i-1], a[i])}
    

    f[i][j][1]也是同理,只需要考虑i和i-1都是否申请上即可。

    时间复杂度O(v^3+nm)

    BZOJ1076 奖励关

    有n轮游戏和m种宝物,每种宝物有分数Pi(可以为负),每轮游戏会等概率抛出一种宝物,你可以选择吃或不吃。第i种宝物还有一个限制集合S表示只有在Si中的宝物都吃过后,才能吃第i种宝物。

    求最优策略下的期望得分。

    n<=100, m<=15

    题解

    当你要做是否吃某个宝物的决策时,如果你知道以吃或不吃的状态进入接下来的几轮游戏时分别的期望得分是多少,那么就可以择优进行决策。

    于是设f[i][S]为还要进行i轮游戏,吃过的宝物集合为S时,接下来能得到的
    最大期望得分。

    f[i][S]= ( ∑Max{ f[i-1][S] , f[i-1][S∪k]+a[k] } )/m

    初始f[0][S]=0。 ans=f[n][0]。

    斜率优化

    斜率优化本身是个很套路的东西。

    它有一个很标准的形式,以及很套路的解法。(总之得需要背过式子)

    hdu3507

    zhhx给的题目解释太诡异了,我换了一个

    给出n个数,要求按顺序全部取出,每次取出一段所花费的费用为取出一段数的和的平方加m,问最小费用是多少

    0 ≤ n ≤ 500000, 0 ≤ M ≤ 1000

    dp设计很简单,主要是优化。
    我们设dp[i]表示输出到i的时候最少的花费, S[i]表示从a[1]到a[i-1]的数字和。

    注意这里为了方便起见前缀和与一般的有区别,就是让式子看起来更好看,没别的特殊意义。

    dp[i] = min{dp[j] + (s[i + 1] - s[j]) ^ 2 + M}(j<i)
    

    然后就是O(N^2)复杂度。

    优化

    那么我们想,能否在O(1)时间内找到所有转移里最优的那个呢?

    我们假设在求解dp[i]时,存在j, kj>k)使得从j转移比从k转移更优,那么需要满足条件:

    dp[j]+(S[i + 1] − S[j]) ^ 2 + M < dp[k] + (S[i + 1] − S[k]) ^ 2 + M;
    

    展开上式

    dp[j] +  s[i + 1] ^ 2 - 2s[i+1]s[j] + s[j] ^ 2 + M < dp[k] + s[i+1] ^ 2 - 2s[i +1]s[k] + s[k]  ^ 2 + m
    

    移项并消去再合并同类项得

    (dp[j] + s[j] ^ 2) - (dp[k] + s[k] ^ 2) < 2s[i + 1 ] * (s[j] - s[k])
    

    这个没啥难度自己推推就行

    会发现最后推出来的式子是一个斜率公式,那把(s[i], f[i])看作一个点,左边就是斜率的形式了。

    当一个数的dp值求完了,它的f值 (f[x]=dp[x]+S[x]^2) 也跟着确定,我们就可以在空间中绘制出点(s[i], f[i])。
    这个点代表已经求出dp值的一个点。
    当我们要求解dp[t]时,如果可用的集合里存在这样三个点,位置关系如图所示:

    综上,不管什么样的S[t+1],从j转移都不会是最佳方案。那么用一个数据结构维护一个凸包(下凸) ,每加入一个点就删去一些点,使其维持凸包的形态。最优转移一定在这个凸包中。

    下凸的凸包边斜率增加,上凸的凸包边斜率减小。

    在凸包里,谁又是最最优呢?

    首先一定数据结构里的凸包一定会是这样的:

    假设 的斜率>2S[t+1]且 的斜率<2S[t+1]从图形特点我们可以发现j点比所有比k小的点都优,比所有比i大的也优。

    所以对于我们二分查找斜率比2S[t+1]小的编号最大的点,就是最优的转移点。由于S[i]也满足单调性,那么如果一个点不是i的最优点了,那么肯定也不是i+1的,我们还可以直接维护一个单调队列就能解决这个问题。

    单调队列每次从后加时,维护凸包。

    每次新计算一个i的dp值,从单调队列队首弹出那些不可能再合法的元素

    斜率优化和几次方没有关系,只是按照套路来做题

    我们会发现换一个题只需要改一改函数里面就行,整体结构是完全一样的

  • 相关阅读:
    微服务架构技术栈选型手册(万字长文)
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    Visual Studio 2013 always switches source control plugin to Git and disconnect TFS
    MFC对话框中使用CHtmlEditCtrl
    ATL开发 ActiveX控件的 inf文件模板
    ActiveX: 如何用.inf和.ocx文件生成cab文件
    Xslt 1.0中使用Array
    如何分隔两个base64字符串?
    An attempt was made to load a program with an incorrect format
    JQuery 公网 CDN
  • 原文地址:https://www.cnblogs.com/this-is-M/p/11330404.html
Copyright © 2011-2022 走看看