您的位置:首页 > 其它

jzoj2754 【2012东莞市选】时间流逝 (概率,赌徒破产问题)

2018-01-21 22:24 417 查看

题面

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


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

分析

这题很日!首先设

令f表示总和为y,剩余物品为z的某一种确切方案,到结束的期望天数.

我们只需要求当y=0,z=n时的f即可(因为只有一种方案嘛)

f=(fa+1)∗p+∑(f′+1)∗1−pz

fa是f的前项(fa取一个转移到f),f’是f的后项 (这里有点难理解,具体来说就是:

先要求f,然后f又要求其他..依次类推….

当前可能会

1.退一个,回到fa

2.进一个,新f’

假如我们可以用A*f+B表示∑f′,

那么就可以用fa表示f,也就是f=fa*A+B,到最后就是A*不存在+B=f[0][1]。

终点就是如果y>T则显然期望是0。

又因为f[0][1]没有前项转移,所以就可以求得f[0][1].

其实就是赌徒破产问题的一个变形。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 35;
typedef double db;
db P,ans;
int T,n,a
;
struct node{db A,B;};
node jy[55]
;
node operator+(node a,node b) {return (node){a.A+b.A,a.B+b.B};}
node operator+(node a,int b) {return (node){a.A,a.B+b};}
node operator*(node a,db b) {return (node){a.A*b,a.B*b};}
node dfs(int s,int x,int dep)  {
if (s>T) return (node){0,0};
if (jy[s][x].A + jy[s][x].B !=0) return jy[s][x];
node now=(node){0,0};
for (int i=1; i<=x; i++) now=now+(dfs(s+a[i],i,dep+1)+1);
if (s==0) {
now=now*(1.0/x);
return jy[s][x]=(node){0,now.B/(1-now.A)};
} else {
now=now*((1-P)/x);
return jy[s][x]=(node){P/(1-now.A),(now.B+P)/(1-now.A)};
}
}

int main() {
freopen("1.in","r",stdin);
while (scanf("%lf %d %d",&P,&T,&n)!=EOF) {
for (int i=1; i<=n; i++) scanf("%d",&a[i]);
sort(a+1,a+1+n);
printf("%.3lf\n",dfs(0,n,0).B);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: