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; }