JLOI2012:时间流逝

Description

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

Solution

状态数很少,是 \(M\) 的正整数划分,大约是 \(10^6\) 左右
搜索出所有的状态,容易发现是一个树形结构
有转移:
\(f[x]=1+p*f[fa]+\frac{1}{|son|}*(1-p)*\sum f[son]\)
树上高斯消元一下就行了

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;
const int N=55,M=2e6+10;
double p;int m,n,a[N],ID=0;
double k[M],b[M];
inline int dfs(int x,int la,int fa,int sz){
    if(x<0)return 0;
    int u=++ID;
    for(int i=la;i>=1;i--)dfs(x-a[i],i,u,la);
    if(u>1){
        double t=(fa==1?1:1-p);
        k[fa]-=t*p/(sz*k[u]);
        b[fa]+=b[u]*t/(sz*k[u]);
    }
    return u;
}
int main(){
    freopen("pp.in","r",stdin);
    freopen("pp.out","w",stdout);
    while(cin>>p>>m>>n){
        ID=0;
        for(int i=1;i<=n;i++)cin>>a[i];
        for(int i=0;i<M;i++)k[i]=1,b[i]=1;
        sort(a+1,a+n+1);
        dfs(m,n,0,0);
        b[1]=b[1]/k[1];
        printf("%.3lf\n",b[1]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Yuzao/p/8961225.html