「题解」老头子的话
作者:互联网
本文将同步发布于:
题目
题目链接:「集训队作业 2018」喂鸽子。
题目描述
老头子是小学校长,小学生(大哥)们都很听老头子的话。一天,老头子给小学生(大哥)们发苹果吃。一共有 \(n\) 个小学生(大哥),老头子每一次会等概率选择一位小学生(大哥)并给他一个苹果。一个小学生(大哥)变得开心当且仅当他拥有的苹果数 \(\geq k\)。
因为老头子年纪大了,所以他想要你告诉他,期望多少次之后所有的小学生(大哥)都变得开心。
\(n\leq 50\),\(k\leq 10^3\)。
题解
简单的 min-max 容斥
设操作序列 \(s\),设第 \(i\) 个人对应的第 \(j\) 次操作为 \(a_{i,j}\),那么
我们求解的是 \(\mathbb{E}(\max\limits_{i=1}^n\{a_i\})\)。
我们不难发现,套用 min-max 容斥的分析方法,有:
\[\mathbb{E}(\max\limits_{i=1}^n\{a_{i,k}\})=\sum_{\mathbb{S}}(-1)^{\left\lvert\mathbb{S}\right\rvert+1}\mathbb{E}(\min_{i=1}^n\{a_{i,k}\}) \]考虑枚举 \(\min\limits_{i=1}^n\{a_{i,k}\}\),那么我们可以通过组合数推出对应的序列个数,从而计算出 \(\mathbb{E}(\min\limits_{i=1}^n\{a_{i,k}\})\)。
用 NTT 优化可以使得复杂度达到 \(\Theta(nk\log_2k)\)。
巧妙构造
上面的做法看上去还是太难了,我们不难想到更加简单的做法。
考虑“有实质变化”的玉米,即喂给了一个没有饱的鸽子的玉米
还是考虑每个“有效玉米序列”的贡献,就是出现概率 \(\times\) 期望
一个固定的“有效玉米序列”,出现概率和期望都和每次扔玉米时已经饱的鸽子有关系
所以状态多记录上饱的鸽子数量。
至于怎样判断一个鸽子饱了,先填“白色”有效玉米,
想让一个鸽子饱了,就钦定之前 \(k-1\) 个白玉米染上色!
所以这个白玉米还是“对未来承诺”,或者对未来预留的 trick。
状态保留贡献和和概率和即可。是可以转移的。
参考程序
#include<bits/stdc++.h>
using namespace std;
#define reg register
typedef long long ll;
const int MAXN=50+5;
const int MAXK=1e3+5;
const int mod=998244353;
inline int add(reg int a,reg int b){
a+=b;
return a>=mod?a-mod:a;
}
inline int sub(reg int a,reg int b){
a-=b;
return a<0?a+mod:a;
}
inline int fpow(reg int x,reg int exp){
reg int res=1;
while(exp){
if(exp&1)
res=1ll*res*x%mod;
x=1ll*x*x%mod;
exp>>=1;
}
return res;
}
int n,k;
int fac[MAXN*MAXK],invfac[MAXN*MAXK],inv[MAXN*MAXK];
inline int binom(reg int n,reg int m){
if(m<0||n<m)
return 0;
else
return 1ll*fac[n]*invfac[m]%mod*invfac[n-m]%mod;
}
int f[MAXN*MAXK][MAXN],g[MAXN*MAXK][MAXN];
int main(void){
scanf("%d%d",&n,&k);
fac[0]=1;
for(reg int i=1;i<=n*k;++i)
fac[i]=1ll*fac[i-1]*i%mod;
invfac[n*k]=fpow(fac[n*k],mod-2);
for(reg int i=n*k-1;i>=0;--i)
invfac[i]=1ll*invfac[i+1]*(i+1)%mod;
for(reg int i=1;i<=n*k;++i)
inv[i]=1ll*invfac[i]*fac[i-1]%mod;
f[0][0]=0,g[0][0]=1;
for(reg int i=0;i<n*k;++i)
for(reg int j=0;j*k<=i;++j){
reg int tmp1=add(1ll*inv[n-j]*f[i][j]%mod,1ll*inv[n-j]*(1ll*n*inv[n-j]%mod)%mod*g[i][j]%mod),tmp2=1ll*inv[n-j]*g[i][j]%mod;
if(j*k<=(i+1))
f[i+1][j]=add(f[i+1][j],tmp1),g[i+1][j]=add(g[i+1][j],tmp2);
if((j+1)*k<=(i+1))
f[i+1][j+1]=add(f[i+1][j+1],1ll*binom(i-j*k,k-1)*tmp1%mod),g[i+1][j+1]=add(g[i+1][j+1],1ll*binom(i-j*k,k-1)*tmp2%mod);
}
reg int ans=1ll*fac[n]*f[n*k][n]%mod;
printf("%d\n",ans);
return 0;
}
标签:mathbb,鸽子,min,int,题解,小学生,的话,老头子,reg 来源: https://www.cnblogs.com/Lu-Anlai/p/14969801.html