zoukankan      html  css  js  c++  java
  • [HNOI2015]亚瑟王

    III.[HNOI2015]亚瑟王

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

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

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

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

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

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

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

    \[f[i][j]=f[i-1][j]\times(1-p_i)^{r-j}+f[i-1][j-1]\times\Big(1-(1-p_i)^{r-j+1}\Big) \]

    我们有

    \[\sum\limits_{j}f[i][j]\times\Big(1-(1-p_i)^{r-j}\Big) \]

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

    复杂度\(O(Tnr\log r)\),假如你用快速幂的话。尽管倒着计算可以将复杂度优化至\(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;
    }
    

  • 相关阅读:
    xcode5.1上真机调试报告No architectures to compile for...的解决办法
    Altium Designer元件库--多单元元器件的制作
    COMS门电路的设计及其优化--以异或门为例
    从器件物理层面看MOSFET的内部结构
    VHDL与Verilog硬件描述语言TestBench的编写
    C语言求解Excel地址转换问题
    数字黑洞求解问题
    计算机显示电池出现问题
    Charles安装
    滑动窗口1——无重复字符的最长字串
  • 原文地址:https://www.cnblogs.com/Troverld/p/14610846.html
Copyright © 2011-2022 走看看