Solution CF2089C2 Key of Like (Hard Version)
UniGravity · · 题解
记当前有
考虑第一个人。每对钥匙和锁的配对成功概率都是
接下来考虑第一个人没选中轮到第二个人,有三种可能:
- 选择第一个锁和任意编号不为一的钥匙。发现相当于配对的钥匙去掉选过的可能有
a+b-1 种选择,成功概率为\frac1{a+b-1} 。 - 选择第一个钥匙和任意编号不为一的锁。这里还需要考虑是假钥匙的概率可能因为之前不匹配而发生变化。一种理解方式是加入
b 个假锁与假钥匙配对,发现概率相当于仍然是\frac1{a+b-1} 。严谨的通过贝叶斯定理的证明可以看 CF 上的题解。 - 钥匙和锁都不选第一个。此时相当于对于某个锁仍然有
a+b 个钥匙可能与其匹配,排除掉与第一个钥匙匹配的结果,成功的概率为(1-\frac1{a+b-1})\frac1{a+b-1}=\frac{a+b-2}{(a+b-1)^2}<\frac1{a+b-1} ,必定更劣。
因此我们发现实际上第二个人绝对会选择第一个锁或钥匙(分别简记为选锁和钥匙)然后任意选择其它的配对。由于每个人会等概率选取所有成功概率相同的操作,并且选钥匙则有
轮到第二个人且选中的概率是
考虑第三个人,还是三种情况。例如如果还是第一个锁与其它钥匙配对,则概率为
于是发现从第二个人之后,每个人都会重复和上个人一样的操作。考虑到某个人成功配对了,我们将配对的钥匙和锁去掉后发现没有任何关于剩下的东西的信息,即之前的操作不会干扰后续的概率!因此我们就把问题转化为
另一种情况是第二个人选了钥匙后到第
接下来就可以 dp 了:记
一种情况是从
另一种情况只在选钥匙时生效,即
同时还要加上恰好在
因此我们发现 dp 可以做到
const int P=1000000007;
int inv[20005];
il void init(int n){
inv[1]=1;forto(i,2,n)inv[i]=1ll*(P-P/i)*inv[P%i]%P;
}
int n,l,k,f[5005][30][105];
il void addto(int &x,int y){x+=y;if(x>=P)x-=P;}
il void delto(int &x,int y){x-=y;if(x<0)x+=P;}
il void work(){
n=read(),l=read(),k=read();
int cnt,s1,s2;ll v1,v2;
forto(a,1,l)forto(b,0,k){
s1=s2=0;
forv(i,n)addto(s1,1ll*(a/n+(i>=n-a%n))*f[a-1][b][i]%P),addto(s2,1ll*((a+b)/n+(i>=n-(a+b)%n))*f[a-1][b][i]%P);
v1=1ll*(a-1)*inv[2*a+b-2]%P*inv[a+b]%P,v2=1ll*(a+b-1)*inv[2*a+b-2]%P*inv[a+b]%P;
if(a==1&&b==0)v1=inv[a+b],v2=0;
forv(i,n){
addto(f[a][b][i],v1*s1%P),addto(f[a][b][i],v2*s2%P);
addto(f[a][b][i],v1*(a/n+(i<a%n))%P),addto(f[a][b][i],v2*((a+b)/n+(i<(a+b)%n))%P);
if(b)addto(f[a][b][i],v1*b%P*f[a][b-1][(i-a%n+n)%n]%P);
addto(s1,f[a-1][b][i]),delto(s1,f[a-1][b][(i-a%n+n)%n]);
addto(s2,f[a-1][b][i]),delto(s2,f[a-1][b][(i-(a+b)%n+n)%n]);
}
}
forv(i,n)printf("%d ",f[l][k][i]);puts("");
forto(a,0,l)forto(b,0,k)forv(i,n)f[a][b][i]=0;
}
signed main(){
init(20000);
int t=read();while(t--)work();
return 0;
}