题目
2n 个人分成2 队玩足球。每队每个球员的队服上有一个1 到n 的正整数(同一个队内的数字不重复)。我们可以知道每个球员的精准度,他可以进行传球的队友集合F 和可以把他的球抢走的敌队球员集合E。当一个球员接到了球,在恰好一秒钟后会发生以下的事件:
1) 该球员把球传给F 集合中的随意一个队员。
2) E 集合中的随意一个敌队球员把球抢走。
3) 该球员射球。
如果该球员射球,他能得分的概率等于他的精准度。在射球之后,不管能否得分,球都会判给敌队的一号球员。发生以上三种不同事件的概率比是|F| : |E| : 1。概率比取决于当前接到球的球员(|S|代表S 集合的规模),而与之前发生的任何事件无关。“随意”的意思是所有在集合F(或E)的球员有相同的概率可以从目前带球的球员得到球(或抢走球)。球在球员之间转移的时间忽略不计。
比赛从1 队的1 号球员带球开始,直到任意一队得到R 分或已经过了T 秒。对于任何可能的最终比分,计算出得出该比分的概率。
会暴力dp的人会发现,暴力会超时,
这题我们可以无视掉球在球员间的传递情况(这个可以预处理),用fi,ti,A,B表示i队开球,到了ti时刻,比分为A:B的概率
这个我们可以通过两个函数得到转移:设gi,j,ti为i队开球,到了ti时刻j进球的概率,delayi,j,ti为i队开球,到了ti时刻,j在控球。(当用delay转移的时候直接把它推到最后时刻,不然会和g转移的有重复)
对于g和delay,我们可以通过函数h获得:设hi,j,k,ti为i队开球,到了ti时刻,球在j队k球员身上。
对于球员间的转移,我们可以预处理出pi1,j1,i2,j2为i1队j1球员传球i2队j2球员的概率。(注意,断球视作传球,没射进看做向对方守门员传球)
进球的概率用shooti1,j1表示。
具体视代码,当然自己想出来就更好了。
贴代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 111
#define T 511
#define R 12
#define EPS 0.0000001
using namespace std;
int n,r,t,nn;
double shoot[2][N],p[2][N][2][N],f[2][T][R][R],g[2][2][T],h[2][2][N][T],ans[R][R],delay[2][T];
void init(){
static int x,y,z;
static double rate,P;
scanf("%d %d %d",&n,&r,&t);
for (int i=0;i<=1;i++)
for (int j=0;j<n;j++){
cin>>rate>>x>>y;
P=(double)1/(x+y+1);
shoot[i][j]=P*rate;
for (int k=1;k<=x;k++)
scanf("%d",&z),p[i][j][i][z-1]=P;
for (int k=1;k<=y;k++)
scanf("%d",&z),p[i][j][!i][z-1]=P;
p[i][j][!i][0]+=P*(1-rate);
}
}
void work(){
h[0][0][0][0]=h[1][1][0][0]=1;
for (int ti=0;ti<t;ti++)
for (int i=0;i<=1;i++)
for (int j=0;j<=1;j++)
for (int k=0;k<n;k++)
if (h[i][j][k][ti])
for (int pp=0;pp<=1;pp++)
for (int x=0;x<n;x++)
h[i][pp][x][ti+1]+=h[i][j][k][ti]*p[j][k][pp][x];
for (int ti=0;ti<t;ti++)
for (int i=0;i<=1;i++)
for (int j=0;j<=1;j++)
for (int k=0;k<n;k++)
g[i][j][ti+1]+=h[i][j][k][ti]*shoot[j][k],delay[i][ti+1]+=h[i][j][k][ti+1];
f[0][0][0][0]=1;
for (int ti=0;ti<t;ti++)
for (int i=0;i<=1;i++)
for (int k=0;k<r;k++)
for (int l=0;l<r;l++){
f[i][t][k][l]+=f[i][ti][k][l]*delay[i][t-ti];
for (int x=1;x<=t-ti;x++)
for (int j=0;j<=1;j++)
f[!j][ti+x][k+!j][l+j]+=f[i][ti][k][l]*g[i][j][x];
}
for (int ti=0;ti<t;ti++)
for (int i=0;i<=1;i++)
for (int j=0;j<r;j++)
ans[j][r]+=f[i][ti][j][r],ans[r][j]+=f[i][ti][r][j];
for (int i=0;i<=1;i++)
for (int j=0;j<=r;j++)
for (int k=0;k<=r;k++)
ans[j][k]+=f[i][t][j][k];
}
void write(){
for (int i=0;i<=r;i++)
for (int j=0;j<=r;j++)
if (ans[i][j]>0)
printf("%.10f\n",ans[i][j]);
}
int main(){
init();
work();
write();
return 0;
}