[HNOI2015]亚瑟王

III.[HNOI2015]亚瑟王

观察题目,我们会发现两个性质:

  1. 一张卡片最多只能在一轮游戏中被成功使用。

  2. 一轮游戏最多只能成功使用一张卡片。

这样,我们纵向考虑每一张卡片,判断它在某局游戏中被成功使用的概率。

设我们当前有t轮游戏,且该卡片成功概率是p。则我们有(1p)t的概率在这局游戏中没有使用它,其余情况则在某局游戏中成功使用。

现在考虑这个t是怎么来的。显然,假如前面的卡片中有s张被使用了,这就相当于占用了s轮,在剩下的rs轮里该卡片才有可能被使用。故此时我们有t=rs

我们设f[i][j]表示前i张卡片里,恰有j张卡片被成功施放的概率。则我们有

f[i][j]=f[i1][j]×(1pi)rj+f[i1][j1]×(1(1pi)rj+1)

我们有

jf[i][j]×(1(1pi)rj)

的概率在所有游戏中成功施放该卡片。故直接用此概率与造成的伤害求积即可得到期望。

复杂度O(Tnrlogr),假如你用快速幂的话。尽管倒着计算可以将复杂度优化至O(Tnr),但是上述复杂度已经可以通过。

代码:

#include<bits/stdc++.h>
using namespace std;
double ksm(double p,int q){
	double r=1;
	for(;q;q>>=1,p=p*p)if(q&1)r=p*r;
	return r;
}
int T,n,m,a[300];
double p[300],res,f[300][300];
int main(){
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		for(int i=0;i<=n;i++)for(int j=0;j<=m;j++)f[i][j]=0;
		for(int i=1;i<=n;i++)scanf("%lf%d",&p[i],&a[i]);
		f[0][0]=1,res=0;
		for(int i=1;i<=n;i++)for(int j=0;j<=min(m,i-1);j++){
			double pos=ksm(1-p[i],m-j);
			f[i][j]+=f[i-1][j]*pos;
			f[i][j+1]+=f[i-1][j]*(1-pos);
			res+=(1-pos)*f[i-1][j]*a[i];
		}
		printf("%.10lf\n",res);
	}
	return 0;
}

posted @   Troverld  阅读(54)  评论(0编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示