zoukankan      html  css  js  c++  java
  • Evanyou Blog 彩带

    题目链接

    题目大意

    题面

    (3) 个骰子,分别有 (k1)(k2)(k3) 面,且骰子掷到某一面的 概率 是相等的。

    (3) 个骰子各掷一次 称作 一轮操作, 每一轮操作会有以下两种情况

    ·当 (k1) 面的骰子的点数为 (a)(k2) 面的骰子的点数为 (b)(k3) 面的骰子的点数为 (c) 时,累加器清零。

    ·否则,累加器累加三个骰子的点数。

    求当累加器大于 (n) 时,需要操作的轮数的期望。

    输入

    第一行一个数 (T) ,一共 (T) 组数据

    下面一共 (T) 行,每行 (7) 个数,分别为 (n)(k1)(k2)(k3)(a)(b)(c)

    输出

    一共 (T) 行,即答案

    题意分析

    这道题涉及了 概率与期望 。大家没有过多的了解,没有关系,你可以在小编Blog中看到《[数论]概率与期望》的讲解。

    我们知道, (E{(X)} = sum P{(i)} imes X{(i)}) ,也就是 (E{(X)} = sum ext{概率} imes ext{权值})

    我们 通常 使用 (DP动规) 来解决 概率与期望 问题

    (dp[i]) 表示累加器为 (i) 时,还需要的轮数的期望。 那么我们来列举 (dp[i]) 进行操作后的结果对应的期望值

    不妨设 清零计数器 的结果为 情况一其他情况二

    那么情况一的概率 (P{(0)}) 易得 (frac{1}{k1 imes k2 imes k3})

    情况二的概率 (P{(k)}) 由于 (k) 的变化,预处理即可

    情况一的期望为 (P{(0)} imes dp[0])
    情况二的期望为 (sum_{k = 3}^{kleq k1+k2+k3} ((A[i + k] imes dp[0] + B[i + k]) imes P{(k)}))

    那么得到 状态转移方程 (dp[i] = P{(0)} imes dp[0] + sum_{k = 3}^{kleq k1+k2+k3} (dp[i+k] imes P{(k)}) + 1)

    为什么(+1)

    新掷一轮的次数也要加进去

    为什么刚才是 (dp) ,现在又跳到待定系数法来了?

    我们发现,刚才列的状态转移方程的 (dp[0])有后效性

    有后效性还叫dp?

    这时候我们就要用到待定系数法了。其实还可以使用高斯消元,只是因为高斯消元时间复杂度过高,故采用待定系数法

    我们知道,对于一个一次函数而言,基本形式都是 (y = a imes x + b)

    我们设两个系数数组: (A[])(B[])

    那么 (dp[i]) 可以表示为 (A[i] imes dp[0] + B[i]),即

    (dp[i] = A[i] imes dp[0] + B[i])标号①

    同理得

    (dp[i + k] = A[i + k] imes dp[0] + B[i + k]) 标号②

    将①和②带入状态转移方程得

    (A[i] imes dp[0] + B[i] = P{(0)} imes dp[0] + sum((A[i + k] imes dp[0] + B[i + k]) imes P{(k)}) + 1)

    此时将等式右边的西格玛拆开,得

    (A[i] imes dp[0]+B[i]=P{(0)} imes dp[0] + sum(A[i + k] imes dp[0] imes P{(k)}) + sum(B[i + k] imes P{(k)}) + 1)

    这时候发现,等式两边的 (dp[0]) 可以对应起来,使得等式左边 (dp[0]) 的系数 (A[i]) ,可以与右边的 (sum(A[i+k] imes P{(k)}))(P{(0)}) 两个系数对应起来,得

    (A[i] = P{(0)} + sum_{k = 3}^{k leq k1+k2+k3}(A[i+k] imes P{(k)}))

    同理对应 (B[i]) 系数,得

    (B[i] = sum_{k = 3}^{k leq k1+k2+k3}(B[i+k] imes P{(k)}) + 1)

    转换问题

    我们按照之前的 (dp[]) 定义,那么 (dp[0]) 将是我们的答案。得

    (dp[0] = A[0] imes dp[0] + B[0])

    (dp[0]) 项都移到左边,化简后得

    (dp[0] = frac{B[0]}{1 - A[0]})

    于是我们从求 (dp[]) 转换为求 (A[])(B[])

    怎么求 (A[])(B[])

    (A[i] = P{(0)} + sum_{k = 3}^{k leq k1+k2+k3}(A[i+k] imes P{(k)}))

    (B[i] = sum_{k = 3}^{k leq k1+k2+k3}(B[i+k] imes P{(k)}) + 1)

    像原本求 (dp[]) 一样,逆序按照递推公式枚举解决即可

    代码

    #include<bits/stdc++.h>
    #include<cctype>
    #pragma GCC optimize(2)
    #define in(a) a = read()
    #define out(a) write(a)
    #define outn(a) out(a),putchar('
    ')
    #define ll long long
    #define rg register
    #define New int
    using namespace std;
    namespace IO_Optimization{
    	inline New read()
    	{
    	    New X = 0,w = 0;
    		char ch = 0;
    
    		while(!isdigit(ch))
    		{
    			w |= ch == '-';
    			ch=getchar();
    		}
    	    while(isdigit(ch))
    		{
    			X = (X << 3) + (X << 1) + (ch ^ 48);
    			ch = getchar();
    		}
    	    return w ? -X : X;
    	}
    
    	inline void write(New x)
    	{
    	     if(x < 0) putchar('-'),x = -x;
    	     if(x > 9) write(x/10);
    	     putchar(x % 10 + '0');
    	}
    
    	#undef New
    }
    using namespace IO_Optimization;
    
    const int MAXN = 600;
    
    double p[MAXN],A[MAXN],B[MAXN];
    int n,k1,k2,k3,a,b,c,T;
    
    int main()
    {
        in(T);
        while(T--)
        {
            memset(p, 0, sizeof(p));
            memset(A, 0, sizeof(A));
            memset(B, 0, sizeof(B));//多组数据清空数组 
            in(n),in(k1),in(k2),in(k3),in(a),in(b),in(c);//输入 
    		int tmp = k1 * k2 * k3;//这个地方纯属优化常数 
            p[0] = 1.0 / tmp; //p[0]
            for(rg int i = 1;i <= k1; ++i) //三重循环预处理所有的概率P(i) 
                for(rg int j = 1;j <= k2; ++j)
                    for(rg int k = 1;k <= k3; ++k)
                    {
                        if(i == a && j == b && k == c) //归零的概率不要累加 
                            continue;
                        p[i+j+k] += p[0];	
                    }
            for(rg int i = n;i >= 0; --i)
            {
                for(rg int j = 3; j <= tmp; ++j)
                {
                    A[i] += A[i+j] * p[j]; 
                    B[i] += B[i+j] * p[j];
                }
                A[i] += p[0]; //A[i] = sigma()  + p0
                B[i] += 1; //B[i] = sigma() + 1
            }
            printf("%.15lf
    ",B[0] / (1-A[0]));
        }
        return 0;
    }
    
  • 相关阅读:
    解决计算机改名无法连接TFS的问题
    MysqlHelper使用反射机制智能推算数据类型以及属性名称
    Cakephp中使用JavaScriptHelper来引入js文件
    CakePHP程序员必须知道的21条技巧
    cakephp文件结构
    去掉字符串前后所有空格
    小程序 支持html富文本吗
    2018年五月博客整理
    Angular cookies
    webstorm 快捷键
  • 原文地址:https://www.cnblogs.com/CJYBlog/p/12251006.html
Copyright © 2011-2022 走看看