题解 P2791 【幼儿园篮球题】
注意:题解所用变量名称和题目中是不同的
题意:给定系数
难度定位:简单紫题,文化课选手应该能秒。
前两档部分分分别是套课本期望方差公式和直接暴力枚举投进几个球,用超几何分布公式计算。
超几何分布中,
所以
考虑
代入题中式子可以得到
交换求和次序
考虑
那么我们可以先硬点 爆
可以得到
因此原式化为下式(与
后面这玩意是一个范德蒙德卷积,进一步化简
这样只要知道
考虑第二类斯特林数
设生成函数
代码
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=5.5e5,M=2e7+2,p=998244353;
int f[N],g[N],r[N],yg[N],ig[N],ifac[M],fac[M],ss[N],mc[N];
int c;
inline int ksm(register int x,register int y)
{
register int r=1;
while (y)
{
if (y&1) r=(ll)r*x%p;
x=(ll)x*x%p;
y>>=1;
}
return r;
}
void dft(register int *a,register int xs,register int limit)
{
register int i,j,k,l,w,wn,b,c;
for (i=1;i<limit;i++) if (i<r[i]) swap(a[i],a[r[i]]);
for (i=1;i<limit;i=l)
{
l=i<<1;
if (xs) wn=ig[l]; else wn=yg[l];
for (j=0;j<limit;j+=l)
{
w=1;
for (k=0;k<i;k++,w=(ll)w*wn%p)
{
b=a[j|k];c=(ll)w*a[j|k|i]%p;
a[j|k]=(b+c)%p;
a[j|k|i]=(b-c+p)%p;
}
}
}
if (xs)
{
limit=ksm(limit,p-2);
for (i=0;i<xs;i++) a[i]=(ll)a[i]*limit%p;
}
}
inline void read(int &x)
{
c=getchar();
while ((c<48)||(c>57)) c=getchar();
x=c^48;c=getchar();
while ((c>=48)&&(c<=57))
{
x=x*10+(c^48);
c=getchar();
}
}
int main()
{
register int n,m,q,k,i,j,x,limit=1,l=0,gs=0;
read(n);read(c);read(q);read(k);
while (limit<=k) limit<<=1,++l;
n=max(n,limit-1);
limit<<=1;
for (i=1;i<limit;i++) r[i]=r[i>>1]>>1|(i&1)<<l;
ig[limit]=ksm(yg[limit]=ksm(3,(p-1)/limit),p-2);
for (i=limit>>1;i;i>>=1)
{
yg[i]=(ll)yg[i<<1]*yg[i<<1]%p;
ig[i]=(ll)ig[i<<1]*ig[i<<1]%p;
}
l=limit>>1;ifac[0]=ifac[1]=fac[0]=fac[1]=1;
for (i=2;i<=n;i++) ifac[i]=p-(ll)p/i*ifac[p%i]%p,fac[i]=(ll)fac[i-1]*i%p;
for (i=2;i<=n;i++) ifac[i]=(ll)ifac[i-1]*ifac[i]%p;
mc[1]=1;
for (i=2;i<l;i++)
{
if (!mc[i]) mc[ss[++gs]=i]=ksm(i,k);
for (j=1;(j<=gs)&&(i*ss[j]<l);j++)
{
mc[i*ss[j]]=(ll)mc[i]*mc[ss[j]]%p;
if (i%ss[j]==0) break;
}
}
for (i=0;i<l;i++) if (i&1) f[i]=p-ifac[i]; else f[i]=ifac[i];
for (i=1;i<l;i++) g[i]=(ll)ifac[i]*mc[i]%p;
dft(f,0,limit);dft(g,0,limit);
for (i=0;i<limit;i++) f[i]=(ll)f[i]*g[i]%p;
dft(f,l,limit);
while (q--)
{
read(n);read(m);read(x);
j=0;
for (i=min(min(x,m),k);i;i--) j=(j+(ll)f[i]*ifac[m-i]%p*fac[n-i]%p*ifac[x-i])%p;
printf("%d\n",int((ll)j*ifac[n]%p*fac[x]%p*fac[m]%p));
}
}
update:由于时限缩短,此代码已经无法通过此题。请使用高效的阶乘/阶乘逆元预处理手段。