Codeforces Gym 101174 D 概率dp

#include<iostream>
#include<stdio.h>
#include <string.h>
using namespace std;
#define LL long long
const int maxn=1e3+10;
#define inf 0x3f3f3f3f
int n,d;
int cnt[51];
int t1,t2,t12;
double dp[12][12][12];
LL c[51][51];
double dfs(int x,int y,int z)
{
    double &cur=dp[x][y][z];
    if(cur!=-1.0)return cur;
    if(z==t12&&(x==t1||y==t2)) return cur=0;
    double tmp=0,self=0;
    for(int a1=0;a1+x<=t1;a1++)
    for(int a2=0;a2+y<=t2&&a1+a2<=d;a2++)
    for(int a12=0;a12+z<=t12&&a1+a2+a12<=d;a12++)
    {
        double poss=
        (c[t1-x][a1]*c[t2-y][a2]*c[t12-z][a12]*
         c[n-(t1-x)-(t2-y)-(t12-z)][d-a1-a2-a12]
        +0.0)/c[n][d];
        if(!a1&&!a2&&!a12) self=poss;
        else tmp+=poss*(dfs(a1+x,a2+y,a12+z)+1);
    }
    return cur=(tmp+self)/(1.0-self);
}
//假设3个集合,X代表A选了B没选的数的集合,Y代表A、B都选了,Z代表A没选B选了
//dp[i][j][k]:=当前X集合中已经选了i个,Y集合中已经选了j个,Z集合中已经选了k个的情况下,游戏结束的期望步数。
//枚举x,y,z
//dp[i][j][k]=Σ(对x!=0,y!=0,z!=0枚举)  c(|X|-i,x)*c(|Y|-j,y)*c(|Z|-k,z)
//*c(n-|X|-|Y|-|Z|+i+j+k,d-x-y-z)/c(n,d) * (dp(i+x,j+y,k+z)+1)

//dp[s0]=sigema((dp[si]+1)*pi)(转入期望和) + (dp[s0]+1)*p0(自环期望和)

//初始状态是dp(|X|,|Y|,k)=dp(i,|Y|,|Z|)=0
//答案是dp(0,0,0)
//c(n,m)是n个中选m个的方案数
//|S|是S集合的大小
// by zwj
int main()
{
    freopen("in.txt","r",stdin);
    for(int i=0;i<51;i++)
        for(int j=0;j<=i;j++)
            c[i][j]=j==0? 1:c[i-1][j-1]+c[i-1][j];
    int sz;
    scanf("%d%d%d",&n,&d,&sz);
    for(int j=0;j<2;j++)
    for(int i=0,x;i<sz;i++)
    {
        scanf("%d",&x);
        cnt[x]|=1<<j;
    }
    for(int i=1;i<=n;i++)
    {
        if(cnt[i]==1)t1++;
        if(cnt[i]==2)t2++;
        if(cnt[i]==3)t12++;
    }
    for(int i=0;i<12;i++)
        for(int j=0;j<12;j++)
            for(int k=0;k<12;k++) dp[i][j][k]=-1;
    double res=dfs(0,0,0);
    printf("%.5f\n",res);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/polya/p/9711031.html