http://codeforces.com/gym/101174/attachments
题意:
给两堆c个球in[1,n],每次随机选出d个求in[1,n],将两堆球中出现在这d个球的球删去,某堆空时结束,问期望次数。
解析:
显然,将球分为4种,A:第一堆独有,B:两堆共有,C:第二堆独有,D,其他
dp[I][J][K]表示ABC三堆分别已经有I,J,K个的期望步数。
考虑一步: 的概率
总方案数为
,上面转移的方案数为
解释一下:前三个是填有用的位置的方案数,最后一个是填无用的方案数
两者之比就是状态转移的概率,我们设为
麻烦的来了,一个状态可能转移到自己(概率设为 )。
根据题面,我们可以得出,这个状态转移的贡献为:(设目标状态期望步数为 )
中间有一步很难想,先求积分,利用 的性质转化后再求导。
代码:
/*
* Author : Jk_Chen
* Date : 2020-03-29-13.57.30
*/
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define rep(i,a,b) for(int i=(int)(a);i<=(int)(b);i++)
#define per(i,a,b) for(int i=(int)(a);i>=(int)(b);i--)
#define mmm(a,b) memset(a,b,sizeof(a))
#define pb push_back
#define pill pair<int, int>
#define fi first
#define se second
void test(){cerr<<"\n";}
template<typename T,typename... Args>void test(T x,Args... args){cerr<<x<<" ";test(args...);}
const LL mod=1e9+7;
const int maxn=1e5+9;
const int inf=0x3f3f3f3f;
LL rd(){ LL ans=0; char last=' ',ch=getchar();
while(!(ch>='0' && ch<='9'))last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
#define rd rd()
/*_________________________________________________________begin*/
int n,d,c;
int A,B,C;
LL CC[52][52];
const double eps=1e-6;
double dp[11][11][11];
double dfs(int I,int J,int K){// 已经有IJK的期望步数
// test(I,J,K);
if(dp[I][J][K]>=-eps)return dp[I][J][K];
if(I+J==A+B||J+K==B+C)return dp[I][J][K]=0;
double &D=dp[I][J][K];
D=0;
double q=0; // 回到自己的概率
rep(i,0,A-I)rep(j,0,B-J)rep(k,0,C-K){// 增加
if(d-i-j-k>n-A-B-C+I+J+K)continue;
if(i+j+k>d)break;
double rate=1.0*CC[A-I][i]*CC[B-J][j]*CC[C-K][k]/CC[n][d]*CC[n-A-B-C+I+J+K][d-i-j-k];
assert(rate>-eps&&rate<=1+eps);
if(i+j+k==0)
q=rate;
else{
double x=dfs(I+i,J+j,K+k);
/* = rate*(1+x) + rate*q*(2+x) + rate*q^2*(3+x)...
= rate*(1+2q+3q^2+4q^3+... + x+qx+q^2x+... )
= rate*((q+q^2+q^3+..)' + x(1+q+q^2+..))
= rate*((q/(1-q))' + x(1/(1-q)))
= rate*(1/(1-q)^2 + x/(1-q))
*/
D+=rate*(1.0/(1-q)/(1-q) + x/(1-q));
}
}
assert(D>-eps);
return D;
}
int main(){
rep(i,0,50)CC[i][0]=1;
rep(i,1,50)rep(j,1,i){
CC[i][j]=CC[i-1][j]+CC[i-1][j-1];
}
n=rd,d=rd,c=rd;
bool vis[52];mmm(vis,0);
A=0,B=0,C=0;
rep(i,1,c){
vis[rd]=1;
}
A=c;
rep(i,1,c){
int num=rd;
if(vis[num])B++,A--;
else C++;
}
mmm(dp,-1);
printf("%.6f\n",dfs(0,0,0));
return 0;
}
/*_________________________________________________________end*/