• bzoj2676 Contra


    题意:

    • 给定N,R,Q,S
    • 有N个关卡,初始有Q条命,且任意时刻最多只能有Q条命
    • 每通过一个关卡,会得到u分和1条命,其中u=min(最近一次连续通过的关数,R)
    • 若没有通过这个关卡,将失去一条命,并进入下一个关卡
    • 若没有生命或N个关卡均已挑战过一次时,游戏结束,得到的分数为每关得到的分数的总和
    • 每条命通过每个关卡的概率为p(0<=p<=1),原先最高分纪录为S
    • 求当p至少为多少时,期望获得的总分能够超过最高分。
    • 1<=N<=10^8 1<=R<=20 1<=Q<=5,输出保留6位小数

    李超WC2013课件里的题(题意就是从课件上粘下来的).

    定义f[i][j][k]为当前有i条命,下一次胜利的得分为j(j=min(当前连胜场次+1,R)),还有k个关卡时的期望得分

    那么f[i][j][k]=p*(f[min(i+1,Q)][min(j+1,R)][k-1]+j)+(1-p)*f[i-1][1][k-1],边界f[0][j][k]=0

    把[i][j]两维展开成一维,就可以通过矩阵乘法来转移了.看起来矩阵会很大会超时,不过我们可以精细地实现程序,因为构造出的转移矩阵里大部分数字是0,我们只需要避免和0相乘就可以过了.(李超在课件里说可以减少无用的状态:连胜次数大于Q的时候生命值不可能小于Q)

    然后我写挂了…原因是数组两维大小(5和20)开反了,把大小为5的一维当作大小为20来用,狂WA….

    #include<cstdio>
    #include<cstring>
    int n,r,q;long long s;
    int sz;
    struct matrix{
      double a[121][121];
      matrix(){memset(a,0,sizeof(a));}
      matrix(int x){memset(a,0,sizeof(a));for(int i=0;i<sz;++i)a[i][i]=x;}
      matrix operator *(const matrix &B)const{
        matrix C;
        for(int i=0;i<sz;++i){
          for(int j=0;j<sz;++j){
        if(a[i][j]<1e-15)continue;
        for(int k=0;k<sz;++k){
          if(B.a[j][k]<1e-15)continue;
          C.a[i][k]+=a[i][j]*B.a[j][k];
        }
          }
        }
        return C;
      }
    }A;
    void QuickPow(matrix &A,int x){//printf("%d
    ",x);
      matrix Ans(1);
      for(;x;x>>=1,A=A*A){//printf("...");
        if(x&1)Ans=Ans*A;
      }
      A=Ans;
    }
    int conv[7][22];//conv[22][7]=>conv[7][22],WA=>AC
    bool check(double ans){
      sz=r*q+1;
      int tot=0;
      for(int i=1;i<=q;++i){
        for(int j=1;j<=r;++j){
          conv[i][j]=tot++;
        }
      }
      A=matrix(0);A.a[tot][tot]=1.0;
      for(int i=1;i<=q;++i){
        for(int j=1;j<=r;++j){
          A.a[tot][conv[i][j]]+=ans*j;
          if(i<q&&j<r){
        A.a[conv[i+1][j+1]][conv[i][j]]+=ans;
          }else if(i<q){
        A.a[conv[i+1][j]][conv[i][j]]+=ans;
          }else if(j<r){
        A.a[conv[i][j+1]][conv[i][j]]+=ans;
          }else{
        A.a[conv[i][j]][conv[i][j]]+=ans;
          }
          if(i>1){
        A.a[conv[i-1][1]][conv[i][j]]+=(1-ans);
          }
        }
      }
      // for(int i=0;i<sz;++i){
      //   for(int j=0;j<sz;++j){
      //     printf("%.2f ",A.a[i][j]);
      //   }printf("
    ");
      // }
      //printf("here");
      QuickPow(A,n);//printf("done");
      double sum=A.a[tot][conv[q][1]];//printf("%f
    ",sum);
      return sum>s;
    }
    int main(){
      scanf("%d%d%d%lld",&n,&r,&q,&s);
      if(!check(1.0)){
        puts("Impossible.");
      }else{//while(1);
        double l=0,r=1.0;
        while(r-l>1e-8){//printf("!");
          double mid=(l+r)/2;
          if(check(mid))r=mid;
          else l=mid;
        }
        printf("%.6f
    ",(r+l)/2);
      }
      return 0;
    }
  • 相关阅读:
    收藏网站代码
    将博客搬至CSDN
    AsyncTask源码浅析
    【转】Activity的launchMode分析 及 Intent.FLAG_NEW_TASK详解
    【转】Java异常:选择Checked Exception还是Unchecked Exception?
    springAOP基本概念和配置
    Java内部类的使用小结
    数据库索引浅析
    基于LinkedBlockingQueue源码自我实现阻塞队列
    【转】HTTP中Get与Post的区别——是我见过说得最全面的
  • 原文地址:https://www.cnblogs.com/liu-runda/p/6403038.html
Copyright © 2020-2023  润新知