UOJ449 【集训队作业2018】喂鸽子

Link
先套一个最值反演,显然大小相同的集合的答案是一样的,所以要求的是\(f_i\)表示\(i\)只鸽子第一次有某只鸽子被喂满的期望次数。最后答案为\(\sum\limits_{i=1}^n(-1)^{i+1}{n\choose i}\frac nif_i\)
现在钦定\(i\)只鸽子,我们称丢给这几只鸽子的玉米为有效玉米,那么取到\(z\)个有效玉米的期望步数就是\(\frac{zn}i\)
那么我们可以枚举有效玉米序列的长度\(j\),计算出有贡献的方案数,然后除以总方案数\(i^j\)
计算有贡献的可以考虑EGF,钦定第一个吃饱的鸽子是\(1\),把最后的方案数乘上\(i\)即可。
那么此时最后一个有效玉米是确定了的,所以只需要知道第一只吃了\(k-1\)个,其它的不超过\(k-1\)个的方案数,可以轻松得到EGF为

\[\frac{x^{k-1}}{(k-1)!}(\sum\limits_{j=0}^{k-1}\frac{x^j}{j!})^{i-1} \]

\(\frac{x^{k-1}}{(k-1)!}\)是容易处理的,那么我们现在只需要处理\((\sum\limits_{j=0}^k\frac{x^j}{j!})^i\)
考虑利用万能的求导,记\(f(x)=\exp x\bmod x^{k+1}\)

\[\begin{aligned} \frac{\mathrm df^i}{\mathrm dx}=if^{i-1}f'=if^{i-1}(f-\frac{x^k}{k!})=if^i-\frac{x^k}{k!}f^{i-1} \end{aligned}\]

#include<cstdio>
#include<cstring>
using i64=long long;
const int N=50007,P=998244353;
i64 fac[N],ifac[N],inv[N],f[N];
void inc(i64&a,i64 b){a+=b-P,a+=a>>63&P;}
void dec(i64&a,i64 b){a-=b,a+=a>>63&P;}
i64 binom(int n,int m){return fac[n]*ifac[m]%P*ifac[n-m]%P;}
i64 pow(i64 a,int b){i64 r=1;for(;b;b>>=1,a=a*a%P)if(b&1)r=r*a%P;return r;}
int main()
{
    int n,k;i64 ans=0;scanf("%d%d",&n,&k),f[0]=fac[0]=fac[1]=inv[0]=inv[1]=ifac[0]=ifac[1]=1;
    for(int i=2;i<=n*k;++i) fac[i]=i*fac[i-1]%P,inv[i]=(P-P/i)*inv[P%i]%P,ifac[i]=inv[i]*ifac[i-1]%P;
    for(int i=1;i<=n;++i)
    {
	static i64 t[N];t[0]=1;i64 sum=0,pw=1;
	if(k!=1) for(int j=i*k;j>=k-1;--j) f[j]=f[j-k+1]*ifac[k-1]%P,f[j-k+1]=0;
	for(int j=1;j<=i*k;++j) t[j]=i*inv[j]%P*(P+t[j-1]-f[j-1])%P;
	memcpy(f,t,sizeof t);
	for(int j=0;j<=i*k;++j) inc(sum,pw*fac[j]%P*f[j]%P),pw=pw*inv[i]%P;
	(i&1? inc:dec)(ans,binom(n,i)*sum%P*n%P*inv[i]%P);
    }
    printf("%lld",ans);
}
posted @ 2020-06-04 20:46  Shiina_Mashiro  阅读(211)  评论(0编辑  收藏  举报