当前位置: 代码迷 >> 综合 >> 51nod 1630 B君的竞技场
  详细解决方案

51nod 1630 B君的竞技场

热度:64   发布时间:2023-10-29 08:12:56.0

题意

我们将竞技场规则简化如下:
1. 每个人进入竞技场后,会等概率随机匹配一个人,匹配到的人与当前胜利和失败场数无关。
2. 胜利达到x场,或失败达到y场后,退出竞技场,根据退出时的胜利场数获得奖励,不能中途放弃。
3. 水平高的选手,总能战胜水平低的选手,不存在水平相等的人。
4. 竞技场有无穷多的人。
B君并不知道自己的水平,你可以认为B君的水平是在所有人中的等概率随机。
B君想知道自己退出时期望胜利场数是多少。

题解

对于这种随机的东西。。表示没什么概念
Q:为什么这个东西不能按50%胜率来算(这个傻逼问题就是我问的)
A:因为对于这个题目,有n个人,你的实力水平在第2,和在第(n?1)(n?1),两者的期望胜场数是没有联系的,所以不可以

Q:样例解释
A:没有。。

怎么做?
我们考虑,题目的意思就是胜率是等概率随机的
如果我们知道了一个胜率p,那么我们就可以DP出答案,f[i][j]f[i][j]表示赢了i场,输了j场的概率。
f[i][j]=f[i?1][j]?(1?p)+f[i][j?1]?pf[i][j]=f[i?1][j]?(1?p)+f[i][j?1]?p
这样的话,我们就可以得到答案了
但是p是不固定的,但是我们知道他在[0,1][0,1]里面随机分布
于是我们可以先用递推式,可以得到一个f[i][j]f[i][j]关于p的多项式
然后就是一个积分问题
求一个导数就可以了
因为项数只有类似于xnxn的形式
直接用xn????>nxn?1xn????>nxn?1就可以得到导数了

CODE:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long double LB;
const int N=25;
int x,y;
LB a[5],b[5];//转移的多项式
LB f[N][N][N*2];//输了i场,赢了j场的多项式
void add (int x,int y,LB xx[],LB yy[])
{f[x][y][0]=max(f[x][y][0],xx[0]+yy[0]-1);for (int u=1;u<=xx[0];u++)for (int i=1;i<=yy[0];i++)f[x][y][u+i-1]=f[x][y][u+i-1]+xx[u]*yy[i];
}
LB getpre(int x,int y)
{LB lalal=0;for (int u=1;u<=f[x][y][0];u++)lalal=lalal+f[x][y][u]/u;return lalal;
}
int main()
{scanf("%d%d",&x,&y);f[0][0][0]=f[0][0][1]=1;a[0]=2;a[1]=0;a[2]=1;b[0]=2;b[1]=1;b[2]=-1;for (int u=0;u<y;u++)for (int i=0;i<x;i++){if (u>0) add(u,i,f[u-1][i],b);if (i>0) add(u,i,f[u][i-1],a);}LB ans=0;for (int u=0;u<y;u++){add(u,x,f[u][x-1],a);ans=ans+getpre(u,x)*x;}for (int u=0;u<x;u++){add(y,u,f[y-1][u],b);ans=ans+getpre(y,u)*u;}printf("%.10Lf\n",ans);return 0;
}