Description
有n个k面骰子。对于i=2…2k,问存在多少种扔骰子的方案使得最终结果不存在两个骰子之和恰好等于i
我们认为所有骰子是一样的
n
,
m
≤
2000
n,m\le2000
n,m≤2000
Solution
首先肯定要枚举这个i
我们发现有些数字是可以随便出现的,其余的数j一定对应了一个数i-j表示它们不能同时出现
并且可以知道当且仅当i为偶数的时候存在一个(i/2,i/2)的对,这时候i/2要么出现一次,要么没有
记有cnt对不能同时出现的数,我们枚举j个被限制的数表示这些数至少出现一次,其余的k-2cnt个可以随便出现
这个问题等价于把n个无差别的球放进j+k-2cnt个盒子里,其中j个盒子不能为空,其余k-2cnt个盒子可以为空。这时答案就是
(
n
+
k
−
2
c
n
t
−
1
j
+
k
−
2
c
n
t
−
1
)
\binom{n+k-2cnt-1}{j+k-2cnt-1}
(j+k−2cnt−1n+k−2cnt−1)
于是答案就是 ∑ j = 0 j ≤ min ( n , c n t ) ( c n t j ) 2 j ( n + k − 2 c n t − 1 j + k − 2 c n t − 1 ) \sum_{j=0}^{j\le\min\left(n,cnt\right)}{\binom{cnt}{j}2^j\binom{n+k-2cnt-1}{j+k-2cnt-1}} ∑j=0j≤min(n,cnt)(jcnt)2j(j+k−2cnt−1n+k−2cnt−1)
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
typedef long long LL;
const int MOD=998244353;
const int N=5005;
int C[N][N],bin[N];
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):v,ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
void pre() {
C[0][0]=bin[0]=1;
rep(i,1,N-1) {
bin[i]=2LL*bin[i-1]%MOD;
C[i][0]=C[i][i]=1;
rep(j,1,i-1) C[i][j]=(C[i-1][j]+C[i-1][j-1])%MOD;
}
}
LL calc(int x,int y,int n) {
LL res=0;
rep(i,0,std:: min(x,n)) {
LL tmp=(LL)C[x][i]*bin[i]%MOD*C[n+y-1][y+i-1]%MOD;
res=(res+tmp)%MOD;
}
return res;
}
int main(void) {
pre();
int k=read(),n=read();
rep(i,2,2*k) {
int cnt=0; LL ans;
rep(j,1,k) cnt+=(i-j>=1&&i-j<=k);
if (i&1) ans=calc(cnt/2,k-cnt,n);
else ans=calc(cnt/2,k-cnt,n)+calc(cnt/2,k-cnt,n-1);
printf("%lld\n", ans%MOD);
}
return 0;
}