zoukankan      html  css  js  c++  java
  • CodeForces

    题目

    传送门

    解法

    比较容易想出一个 (mathtt{dp}):令 (dp_{i,j,k}) 为前 (i) 天赢了 (j) 场,剩余容量为 (k)​ 的概率。转移方程就是:

    [dp_{i,j,k}=dp_{i-1,j,k}cdot (1-p_i)+dp_{i-1,j-1,k-a_i}cdot p_i ]

    看似 (k) 这一维比较大,但是实际上我们可以将其限制在 (n) 的范围,也即 (200)​ 以内。因为只要容量到达了 (200) 就一定够减了,而且转移方程的系数与 (k) 无关。相当于最后统计 (sum_{i=l}^nsum_{j=0}^{200}{dp_{n,i,j}})。这样就是 (mathcal O(n^3))

    但是实际上这样转移是有一定问题的。我们可以先获得后面的容积,然后再得到前面的物品。不妨将容积扩大到 ([0,400]),最后取剩余容量在 ([200,400])(dp) 值即可。

    代码

    #include <cstdio>
    #include <iostream>
    using namespace std;
    
    int n, l, k, val[205];
    double dp[205][205][405], p[205], ans;
    
    int read() {
        int x = 0, f = 1; char s;
        while((s = getchar()) < '0' || s > '9') if(s == '-') f = -1;
        while(s >= '0' && s <= '9') {x = (x << 1) + (x << 3) + (s ^ 48); s = getchar();}
        return x * f;
    }
    
    int main() {
        n = read(), l = read(), k = read();
        for(int i = 1; i <= n; ++ i) scanf("%lf", &p[i]), p[i] /= 100;
        for(int i = 1; i <= n; ++ i) val[i] = read();
        dp[0][0][k + 200] = 1;
        for(int i = 0; i < n; ++ i)
            for(int j = 0; j <= i; ++ j)
                for(int v = 0; v <= 400; ++ v) {
                    int s = min(400, v + val[i + 1]);
                    dp[i + 1][j][v] += dp[i][j][v] * (1.0 - p[i + 1]);
                    if(s >= 0) dp[i + 1][j + 1][s] += dp[i][j][v] * p[i + 1];
                }
        for(int i = l; i <= n; ++ i)
            for(int j = 200; j <= 400; ++ j)
                ans += dp[n][i][j];
        printf("%.10f
    ", ans);
        return 0;
    }
    
  • 相关阅读:
    Zabbix基本配置及监控主机
    利用XAG在RAC环境下实现GoldenGate自动Failover
    Oracle Database 12c Data Redaction介绍
    使用Oracle官方巡检工具ORAchk巡检数据库
    浅谈C# 多态
    Qt 操作Excel
    一个适用于任何继承于QObject的类的创建工厂
    QT5 控件增加背景图片(可缩放可旋转)的几种方法
    值得推荐和学习的C/C++框架和库
    gcc/g++编译
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12665883.html
Copyright © 2011-2022 走看看