Description
有0~k-1共k束花,每一束花中有m种颜色的花,第i种颜色有e[i]朵
第x次操作将会从第x%k束花中摘走至少一朵花,当一朵花被摘完游戏结束
对于i=0~k-1输出游戏在第i个位置恰好结束的方案数
Solution
每次至少摘一朵,那么游戏至多进行
n
=
∑
i
=
1
m
e
i
n=\sum_{i=1}^{m}e_i
n=∑i=1mei轮
设
f
(
x
)
f(x)
f(x)表示在某个位置第x轮恰好结束的方案数,可以发现
f
(
x
)
f(x)
f(x)同时也对应恰好在第x轮结束的方案数,我们钦定最后一次全拿完就可以了
于是第i个位置的答案就是
∑
j
=
0
n
f
(
j
+
1
)
i
−
1
f
(
j
)
k
−
j
+
1
\sum\limits_{j=0}^{n}{f\left(j+1\right)}^{i-1}{f\left(j\right)}^{k-j+1}
j=0∑nf(j+1)i−1f(j)k−j+1
考虑怎么求
f
(
x
)
f(x)
f(x),我们可以看成是把x个球染上m种颜色分到k个盒子里面,要求每个盒子里不同颜色的球数量之和非零,而某种颜色的球在某个盒子里可以不放。
我们设
g
(
x
)
=
∏
i
=
1
m
(
e
i
+
x
−
1
x
−
1
)
g(x)=\prod\limits_{i=1}^{m}\binom{e_i+x-1}{x-1}
g(x)=i=1∏m(x−1ei+x−1),那么
f
(
x
)
f(x)
f(x)就可以枚举空的位置容斥求了。于是有
f
(
x
)
=
∑
y
=
0
x
(
−
1
)
x
−
y
(
x
y
)
g
(
y
)
f(x)=\sum\limits_{y=0}^{x}{{\left(-1\right)}^{x-y}\binom{x}{y}g(y)}
f(x)=y=0∑x(−1)x−y(yx)g(y)
Code
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=985661441;
const int N=2000005;
int rv[N],p[N],e[N];
LL fac[N],inv[N],f[N],g[N];
void upd(LL &x,LL v) {
x+=v,(x>=MOD)?(x-=MOD):0;
}
LL ksm(LL x,LL dep) {
LL res=1;
for (;dep;dep>>=1,x=x*x%MOD) {
(dep&1)?(res=res*x%MOD):0;
}
return res;
}
void NTT(LL *a,int n,int f) {
for (int i=0;i<n;++i) if (i<rv[i]) std:: swap(a[i],a[rv[i]]);
for (int i=1;i<n;i<<=1) {
LL wn=ksm(3,(f==1)?((MOD-1)/i/2):(MOD-1-(MOD-1)/i/2));
for (int j=0;j<n;j+=(i<<1)) {
LL w=1;
for (int k=0;k<i;++k,w=w*wn%MOD) {
LL u=a[j+k],v=a[j+k+i]*w%MOD;
upd(a[j+k],v),a[j+k+i]=MOD-v;
upd(a[j+k+i],u);
}
}
}
if (f==-1) {
LL ny=ksm(n,MOD-2);
for (int i=0;i<n;++i) a[i]=a[i]*ny%MOD;
}
}
LL C(int n,int m) {
if (m>n||m<0) return 0;
return fac[n]*inv[m]%MOD*inv[n-m]%MOD;
}
int main(void) {
freopen("data.in","r",stdin);
fac[0]=fac[1]=inv[0]=inv[1]=1;
rep(i,2,N-1) {
fac[i]=fac[i-1]*i%MOD;
inv[i]=inv[MOD%i]*(MOD-MOD/i)%MOD;
}
rep(i,2,N-1) inv[i]=inv[i-1]*inv[i]%MOD;
int n,m,k,T=0;
while (~scanf("%d%d",&m,&k)) { n=0;
rep(i,1,m) {scanf("%d%d",&p[i],&e[i]),n+=e[i];}
int len=1,lg=0;
for (;len<=n*2;) len<<=1,++lg;
for (int i=0;i<len;++i) rv[i]=(rv[i>>1]>>1)|((i&1)<<(lg-1));
for (int i=0;i<len;++i) f[i]=g[i]=0;
rep(i,0,n) g[i]=1;
rep(i,0,m) rep(j,0,n) g[j]=g[j]*C(e[i]+j-1,j-1)%MOD;
rep(i,0,n) {
f[i]=inv[i]; (i&1)?(f[i]=MOD-f[i]):0;
g[i]=g[i]*inv[i]%MOD;
}
NTT(f,len,1),NTT(g,len,1);
for (int i=0;i<len;++i) f[i]=f[i]*g[i]%MOD;
NTT(f,len,-1);
rep(i,0,n) f[i]=f[i]*fac[i]%MOD; f[n+1]=0;
printf("Case #%d: ", ++T);
rep(i,1,k) {
LL ans=0;
rep(j,0,n) upd(ans,ksm(f[j+1],i-1)*ksm(f[j],k-i+1)%MOD);
if (i==k) printf("%lld\n", ans);
else printf("%lld ", ans);
}
}
return 0;
}