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

    (\)

    (Description)


    (N)张有顺序排好的牌,每张牌有伤害值(v_i)和发动概率(p_i),游戏进行(K)轮,每轮都按顺序扫描,按照以下规则:

    • 若当前牌在前面的轮中未发动过:

      • (p_i)的概率发动,造成(v_i)的伤害,结束该轮;

      • (1-p_i)的概率不发动,扫描下一张牌,若是最后一张就结束该轮;

    • 若当前牌在前面的轮中发动过:

      • 扫描下一张牌,若是最后一张就结束该轮。

    求出这一套卡牌在这(K)轮游戏中能造成的总伤害的期望。 (T)组测试数据。

    • (Tin [1,444],Nin [1,220],Kin[0,132],p_iin[0,1],v_iin[0,1000])

    (\)

    (Solution)


    • 每张牌造成的伤害是固定且独立的,根据期望的线性性,总的期望等于每张牌的期望之和,每张牌的期望等于这张牌发动的概率乘以造成的伤害。而伤害是固定的,所以只需要求出每张牌被发动的概率就好。

    • 这个(DP)思路还是很可以的虽然最后还是抄了题解。他并没有将每一轮分开考虑,而是直接考虑全部的(K)轮。同时,他没有对每一张牌独立考虑,而是对一个前缀的所有牌放到一起考虑。设(f[i][j])表示(K)轮中,前(i)张牌中发动了(j)张的概率。有边界(f[0][0]=1.0),然后递推的时候分为第(i)张牌是否发动考虑:

      • 不发动((j<i)):所以前( i-1)张牌里发动了(j)张,这部分的概率是(f[i-1][j])。然后考虑当前不发动的限制,前(i-1)张中的发动的那(j)张对应的回合里,发动之后这一轮就结束了,所以当前位置没有被考虑到的可能,不发动的概率为(1),而剩下在后(N-i)张里,有(K-j)张要被发动,他们都经过了第(i)张的位置,这些回合中第(i)张牌不能发动,所以有

        [f[i][j]+=f[i-1][j] imes(1-p_i)^{K-j} ]

      • 发动((j ot=0)):前(i-1)张中发动了(j-1)(f[i-1][j-1])。同样的思路那(j)张牌对应的位置不会考虑到当前牌,当前牌在剩下的(K-j+1)轮里挑一轮发动就好了。而容斥起来非常麻烦,用常用的与或转化,不发动是与的条件,所以发动的概率为((1-(1-p_i)^{K-j+1})),所以有

        [f[i][j]+=f[i-1][j-1] imes(1-(1-p_i)^{K-j+1}) ]

    • 考虑如何组合出每一张牌发动的概率,跟第二类转移的思路类似,设(q_i)表示第(i)张牌在这(K)轮中发动的概率,前面发动任意张数都不需要考虑当前位置,在剩下的轮里挑一轮发动就好了

      [q_i=sum_{j=1}^{min(i,K)-1} f[i-1][j] imes (1-(1-p_i)^{K-j}) ]

    • 根据期望的线性性有(E(sum)=sum_{i=1}^n q_i imes v_i)

    (\​)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 300
    #define R register
    #define gc getchar
    using namespace std;
     
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
     
    inline double rdd(){
      double x=0,base=1; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=x*10+(c^48);c=gc();}
      if(c=='.'){
        c=gc();
        while(isdigit(c)){x+=(base/=10)*(c^48);c=gc();}
      }
      return f?-x:x;
    }
     
    int n,m,val[N];
    double p[N],mul[N][N],f[N][N];
     
    inline void work(){
      n=rd(); m=rd();
      for(R int i=1;i<=n;++i) p[i]=rdd(),val[i]=(double)rd();
      for(R int i=1;i<=n;++i){
        mul[i][0]=1.0; f[i][0]=0;
        for(R int j=1;j<=m;++j) f[i][j]=0,mul[i][j]=mul[i][j-1]*(1.0-p[i]);
      }
      f[0][0]=1.0;
      for(R int i=1;i<=n;++i)
        for(R int j=0;j<=min(i,m);++j){
          if(j) f[i][j]+=f[i-1][j-1]*(1.0-mul[i][m-j+1]);
          if(i!=j) f[i][j]+=f[i-1][j]*mul[i][m-j];
        }
      R double ans=0.0,cnt=0.0;
      for(R int i=1;i<=n;++i){
        cnt=0.0;
        for(R int j=0;j<=min(i-1,m);++j) cnt+=f[i-1][j]*(1.0-mul[i][m-j]);
        ans+=cnt*val[i];
      }
      printf("%.10lf
    ",ans);
    }
     
    int main(){
      int t=rd();
      while(t--) work();
      return 0;
    }
    
  • 相关阅读:
    【Java EE 学习 36】【struts2】【struts2系统验证】【struts2 ognl值栈】【struts2 ongl标签】【struts2 UI标签】【struts2模型驱动和令牌机制】
    【Java EE 学习 35 下】【struts2】【struts2文件上传】【struts2自定义拦截器】【struts2手动验证】
    【Java EE 学习 35 上】【strus2】【类型转换器】【struts2和Servlet API解耦】【国际化问题】【资源文件乱码问题已经解决】
    【Java EE 学习 34】【struts2学习第一天】
    【JavaScript中的正则表达式】
    【Java EE 学习 33 下】【validate表单验证插件】
    【Java EE 学习 33 上】【JQuery样式操作】【JQuery中的Ajax操作】【JQuery中的XML操作】
    【Java EE 学习 32 下】【JQuery】【JQuey中的DOM操作】
    【Java EE 学习 32 上】【JQuery】【选择器】
    【Java EE 学习 31】【JavaScript基础增强】【Ajax基础】【Json基础】
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9715041.html
Copyright © 2011-2022 走看看