zoukankan      html  css  js  c++  java
  • BZOJ2784:[JLOI2012]时间流逝

    Description

    生活可以很简单。可以探索水底世界的神秘,也可以去发现奇特新生物,亦或踏上一段新生的旅程。在必须要迎接挑战或跟周围的生物进行生存争夺之前,享受自由的飞翔。此时你会觉得生活是如此美好。
    像蛇喜欢吃浮游生物一样(哦,我好像忘记告诉你这个常识),每天,你可以吃一些你周围的基础生物,然后会在你的尾巴上得到一个能量圈。你将会有好多种不同的能量圈,每一个都会被赋予一个能量。你可以拥有多个同种的能量圈,但是对于新得到的相同的能量圈,它的能量不能大于你已拥有的任何一个能量圈。除了前面的规则,获得新的能量圈的种类的概率是一样的。一天天过去,你得到越来越多的能量,开始了进化演变。
    但是你也有自己的问题,有时你会面对邪恶的果冻鱼。它会追着你咬你,你不得不扔出最小能量值的能量圈然后赶忙逃跑。在这种情况下,你不会有任何的胃口了,因此这天你将不再得到任何能量圈。幸好,当你没有任何能量圈的时候,果冻鱼就算看见你也不会追着你,此时你可以好好地享用美食。
    你听说当你的总的能量值超过了某个阈值之后,可以进化成强大模式并能够吃掉果冻鱼。是时候反击了!下面是本题的问题:预计要过多少天你才能进化成强大模式?(第一天默认你没有任何能量圈)

    Input

    输入包含多个测例。对每个测例会有两行。第一行是一个浮点数P,一个整数T和一个整数N。P是每天遇到果冻鱼的概率,T是阈值。第二行是N个不同的正整数,表示每一种能量圈的能量值。

    Output

    对于每个测例,输出一行表示预计要过多少天你的能量值能够超过阈值,四舍五入到三位小数。

    Sample Input

    0.5 0 1
    1
    0.5 1 2
    1 2

    Sample Output

    1.000
    2.000

    HINT

    对于所有数据,0.1≤P≤0.9,1≤T≤50,1≤N≤30。

    题解:

    概率DP题,我想了好久以后开始写,调了好几个小时都没有写对。

    直到我看了czt的代码,我在发现我原本推出的状态转移方式是错误的。

    正确的DP方式:

    用[i,j]记录已经筹集了i的能量,且拥有的最小能量圈为j,让其发展下去,直到筹集t以上的能量或失去j能量圈为止的情况。

    用f[i,j,1]记录有多大的几率在能量满之前会失去j能量圈,用f[i,j,2]记录能量满或失去j的期望天数。

    初始状态:f[i,j,1]=0,f[i,j,2]=0。(i>=t) 假设[i,j]时获得了一个k的能量圈(k<=j),则f[i,j]可以通过f[i+k,k]转移而来。

    设x[k]为当前获得k的概率。

    原地踏步(即获得k后进入[i+k,k]状态却失去k)的概率p1为∑(f[i+k,k,1]*x[k])。

    没有原地踏步的概率p2为1-p1。

    从[i,j]开始,直到第一次因为失去k而回到[i,j]或者能量满的 概率*期望步数 之和tot为∑((f[i+k,k,2]+1)*x[k])。

    推一推公式,可得f[i,j,1]=p/p2,f[i,j,2]=(tot/p2)+f[i,j,1]*1。

    对于没有能量圈的状态(即答案),不会遇到鱼,转移方式与上面的略有不同,但大致是一样的。

    代码:

     1 var
     2   i,j,k,l,n,m,t:longint;
     3   p1,p2:extended;
     4   b:array[0..1000,0..100,1..2]of extended;
     5   lb,qz:array[0..100]of longint;
     6   ans:extended;
     7 begin
     8   while not eof do
     9   begin
    10     fillchar(lb,sizeof(lb),0);
    11     fillchar(qz,sizeof(qz),0);
    12     fillchar(b,sizeof(b),0);
    13     readln(p1,t,n); inc(t); p1:=1-p1;
    14     for i:=1 to n do begin read(j); inc(lb[j]); end; readln;
    15     for i:=1 to 100 do qz[i]:=qz[i-1]+lb[i];
    16     for i:=t-1 downto 1 do
    17     for j:=1 to 100 do
    18     if lb[j]>0 then
    19     begin
    20       p2:=1;
    21       for k:=1 to j do
    22       if lb[k]>0 then
    23       begin
    24         if i+k<t then
    25         begin
    26           p2:=p2-p1*(lb[k]/qz[j])*b[i+k,k,1];
    27           b[i,j,2]:=b[i,j,2]+p1*(lb[k]/qz[j])*(1+b[i+k,k,2]);
    28         end else b[i,j,2]:=b[i,j,2]+p1*(lb[k]/qz[j]);
    29       end;
    30       b[i,j,1]:=(1-p1)/p2; b[i,j,2]:=b[i,j,2]/p2;
    31       b[i,j,2]:=b[i,j,2]+b[i,j,1];
    32     end;
    33     p2:=1; ans:=0;
    34     for k:=1 to 100 do
    35     if lb[k]>0 then
    36     begin
    37       if k<t then
    38       begin
    39         p2:=p2-(lb[k]/n)*b[k,k,1];
    40         ans:=ans+(lb[k]/n)*(1+b[k,k,2]);
    41       end else ans:=ans+lb[k]/n;
    42     end;
    43     writeln((ans/p2):0:3);
    44   end;
    45 end.
    View Code
  • 相关阅读:
    3、UML中的类图及类图之间的关系
    2、GoF的23种设计模式
    1、软件设计模式概念
    枚举
    泛型
    MySQL
    蚁群算法MATLAB解VRP问题
    蚁群算法MATLAB解TSP问题
    模拟退火解TSP问题MATLAB代码
    模拟退火学习
  • 原文地址:https://www.cnblogs.com/GhostReach/p/6327372.html
Copyright © 2011-2022 走看看