题面传送门

感觉是道挺好的题,可惜当时没写题解来着的?

根据期望的线性公式,我们求出每个卡牌被发动的概率 \(q_i\),然后

\[ans=\sum\limits_{i=1}^np_id_i
\]

于是我们求出 \(q_i\) 即可。

我们设 \(dp_{i,j}\) 表示在前 \(i\) 张牌里发动了 \(j\) 张牌的概率。

如果已知 \(dp_{i,j}\),那么可以这样求出 \(q_i\):

\[q_i=\sum\limits_{j=0}^rdp_{i-1,j}+(1-(1-p_i)^{r-j})
\]

稍微解释一下这个式子。我们枚举在前 \(i-1\) 个牌里面发动了 \(j\) 个牌。这意味着有 \(j\) 轮不会考虑到第 \(i\) 张牌。在剩下 \(r-j\) 轮当中,\(i\) 号卡牌一次都没被发动的概率为 \((1-p_i)^{r-j}\),\(1-(1-p_i)^{r-j}\) 就是卡牌 \(i\) 至少被发动一次的概率。

那么怎样求 \(dp_{i,j}\) 呢,其实用背包的套路就可以了。分两种情况:

  1. 如果卡牌 \(j\) 被选,那么 \(dp_{i,j}\) 可以从 \(dp_{i-1,j-1}\) 转移过来。有 \(r-j+1\) 轮会考虑到卡牌 \(i\),卡牌 \(i\) 发动的概率为 \((1-(1-p_i)^{r-j+1})\)。
  2. 如果卡牌 \(j\) 没被选,那么 \(dp_{i,j}\) 可以从 \(dp_{i-1,j}\) 转移过来。有 \(r-j\) 轮会考虑到卡牌 \(i\),卡牌 \(i\) 未被发动的概率为 \((1-p_i)^{r-j}\)。

综上 \(dp_{i,j}=dp_{i-1,j-1}\times(1-(1-p_i)^{r-j+1})+dp_{i,j}\times(1-p_i)^{r-j}\)

于是这题就做完了,复杂度 \(\mathcal O(Tnr)\)。

另外预处理 \(1-p_i\) 的幂。快速幂会多一个 \(\log\)

#include <bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define fz(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define foreach(it,v) for(__typeof(v.begin()) it=v.begin();it!=v.end();it++)
#define all(a) a.begin(),a.end()
#define fill0(a) memset(a,0,sizeof(a))
#define fill1(a) memset(a,-1,sizeof(a))
#define fillbig(a) memset(a,0x3f,sizeof(a))
#define y1 y10101010101
#define y0 y01010101010
typedef pair<int,int> pii;
typedef long long ll;
int T,n,r,d[222];
double p[222],dp[222][222];
double pw[222][222];
inline void clear(){
for(int i=1;i<=n;i++) d[i]=0;
for(int i=1;i<=n;i++) p[i]=0;
for(int i=0;i<=n;i++) for(int j=0;j<=n;j++) dp[i][j]=0;
for(int i=0;i<=n;i++) for(int j=0;j<=r;j++) pw[i][j]=0;
}
inline void solve(){
scanf("%d%d",&n,&r);clear();//remember to clear the data!
for(int i=1;i<=n;i++) scanf("%lf%d",&p[i],&d[i]);
for(int i=1;i<=n;i++){
pw[i][0]=1;
for(int j=1;j<=r;j++){
pw[i][j]=pw[i][j-1]*(1.0-p[i]);//calculate the power of 1-p[i]
// printf("%d %d %.10lf\n",i,j,pw[i][j]);
}
}
dp[0][0]=1;
for(int i=1;i<=n;i++) for(int j=0;j<=i;j++){
dp[i][j]=dp[i-1][j]*pw[i][r-j];
if(j) dp[i][j]+=dp[i-1][j-1]*(1-pw[i][r-j+1]);//calculate dp[i][j] using the fomula above
// printf("%d %d %.10lf\n",i,j,dp[i][j]);
}
double ans=0;
for(int i=1;i<=n;i++){
double prob=0;
for(int j=0;j<=i-1;j++){
prob+=dp[i-1][j]*(1-pw[i][r-j]);//calculate p[i]
}
// printf("%d %.10lf\n",i,prob);
ans+=prob*d[i];
}
printf("%.10lf\n",ans);
}
int main(){
scanf("%d",&T);
while(T--) solve();
return 0;
}
/*
2
3 2
0.5000 2
0.3000 3
0.9000 1
3 2
0.5000 2
0.3000 3
0.9000 1
*/

洛谷 P3239 [HNOI2015]亚瑟王(期望+dp)的更多相关文章

  1. 洛谷 P3239 [HNOI2015]亚瑟王(期望dp)

    题面 luogu 题解 一道复杂的期望\(dp\) 思路来源:__stdcall 容易想到,只要把每张牌打出的概率算出来就可以求出\(ans\) 设\(fp[i]\)表示把第\(i\)张牌打出来的概率 ...

  2. [洛谷 P3239] [HNOI2015]亚瑟王

    [HNOI2015]亚瑟王 题目描述 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑.他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂亮.众所周知, ...

  3. P3239 [HNOI2015]亚瑟王 期望dp

    这个题一看就是期望dp,但是我有个问题,一个事件的期望等于他所有事件可能行乘权值的和吗...为什么我有天考试的时候就不对呢...求大佬解释一下. 至于这道题,f[i][j]代表前i个有j个发动技能,这 ...

  4. 洛谷P3239 [HNOI2015]亚瑟王

    题目描述 小 K 不慎被 LL 邪教洗脑了,洗脑程度深到他甚至想要从亚瑟王邪教中脱坑.他决定,在脱坑之前,最后再来打一盘亚瑟王.既然是最后一战,就一定要打得漂亮.众所周知,亚瑟王是一个看脸的游戏,技能 ...

  5. P3239 [HNOI2015]亚瑟王 期望 dp

    LINK:亚瑟王 Saber!Excalibur! 比较难的期望dp. 可以发现如果暴力枚举所有的局面复杂度很高 . 转换的思路则是 期望的线性性. 求出每张牌的期望累加即可. 考虑每张牌的期望=这张 ...

  6. 洛谷P3239 [HNOI2015]亚瑟王(期望dp)

    传送门 stdcall大佬好强 期望的姿势不是很高……据大佬说期望有一个线性性质,也就是说可以把每一张牌的期望伤害算出来然后再加起来就是总的期望伤害 因为每一张牌只能用一次,我们设$dp[i]$表示第 ...

  7. P3239 [HNOI2015]亚瑟王——概率DP

    题面:亚瑟王 最近考试考期望很自闭啊,没做过这种类型的题,只能现在练一练: 所谓期望,就是状态乘上自己的概率:对于这道题来说,我们要求的是每张牌的伤害乘上打出的概率的和: 当然不是直接乘,因为给的是每 ...

  8. BZOJ4008: [HNOI2015]亚瑟王(期望dp)

    Time Limit: 20 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 1952  Solved: 1159[Submit][Status] ...

  9. [HNOI2015]亚瑟王(期望+DP)

    题解 利用期望的线性性,可以把问题转化为求每一个卡牌造成期望的期望值. 然后我们就需要知道每一个卡牌发动技能的概率. 因为当某一张卡牌发动技能时这一轮会结束,这就很难直接计算了. 我们使用DP 设dp ...

随机推荐

  1. 剑指offer:JZ8 二叉树的下一个结点

    JZ8 二叉树的下一个结点 描述 给定一个二叉树其中的一个结点,请找出中序遍历顺序的下一个结点并且返回.注意,树中的结点不仅包含左右子结点,同时包含指向父结点的next指针.下图为一棵有9个节点的二叉 ...

  2. Java:ConcurrentHashMap类小记-3(JDK8)

    Java:ConcurrentHashMap类小记-3(JDK8) 结构说明 // 所有数据都存在table中, 只有当第一次插入时才会被加载,扩容时总是以2的倍数进行 transient volat ...

  3. 通过Nacos动态刷新Spring Cloud Gateway的路由

    通过Nacos动态刷新Spring Cloud Gateway的路由 一.背景 二.解决方案 三.实现功能 四.实现步骤 1.网关服务的实现 1.pom文件 2.bootstrap.yml配置文件 3 ...

  4. Noip模拟15 2021.7.14

    T1 夜莺与玫瑰 题目越发的变态起来... 这题刚开始看超级像仪仗队,好不容易码完欧拉函数后尝试×2后输出但不对!! 于是选择了跳过.... 正解居然是莫比乌斯函数....我也是醉了 预处理完就剩下$ ...

  5. PCB电路板元器件布局的一般原则*(转)

    PCB电路板元器件布局的一般原则: 设计人员在PCB电路板布局过程中需要遵循的一般原则如下. (1)元器件最好单面放置.如果需要双面放置元器件,在底层(Bottom Layer)放置插针式元器件, ) ...

  6. 关于linux的fork的一点学习总结

    最近操作系统的实验要用到fork,于是去搜索了一下资料,很幸运地在博客中找到一篇深度好文: http://blog.csdn.net/jason314/article/details/5640969 ...

  7. Java中Lambda表达式的进化之路

    Lambda表达式的进化之路 为什么要使用Lambda表达式 可以简洁代码,提高代码的可读性 可以避免匿名内部类定义过多导致逻辑紊乱 在原先实现接口抽象方法的时候,需要通过定义一个实现接口的外部类来实 ...

  8. DeWeb 电脑和手机动态适配

    DeWeb 做多平台适配很方便! 多平台适配代码在OnMouseUp中. X,Y分别表示当前设备的Width/Height: Button : mbLeft : 屏幕纵向, mbRight:屏幕横向: ...

  9. C++ Qt 项目实战(一)之文本编辑器

    文本编辑器例图 项目开发环境 系统版本:windows10 QT 版本: 5.9.9 开发语言:C++ 已实现功能 文件操作:新建,打开,保存,另存为,打印,退出 编辑操作:复制,粘贴,剪切,查找,替 ...

  10. uni-app nvue页面动态修改导航栏按钮

    话不多说上代码 let pages = getCurrentPages() let page = pages[pages.length - 1]; let currentWebview = page. ...