CF1765C Card Guessing
桌面上有一堆牌,牌有四种花色,每种花色有 n n n张,一共 4 n 4n 4n找张。每次随机从牌堆中抽一张直到抽完,抽出卡片的序列总共有 ( 4 n ) ! (4n)! (4n)!种。Monocarp在每次抽卡时会根据过去 k k k次抽卡的结果来猜当前抽出卡牌的花色,他会固定猜最近 k k k次结果中出现次数最小的那一个花色(如果有多种花色则任意选一个,如果之前抽卡数量小于 k k k则猜测依据是之前所有的抽卡结果)。求期望猜对的次数,输出答案模 998244353 998244353 998244353。
1 ≤ n ≤ 500 1\leq n\leq 500 1≤n≤500, 1 ≤ k ≤ 4 × n 1\leq k\leq 4\times n 1≤k≤4×n
根据期望的线性性,期望猜对的次数等于每次猜对的概率之和。若当前是第 i i i次猜测,设 t = min ( k , i − 1 ) t=\min(k,i-1) t=min(k,i−1),那么是否猜对只取决于第 i − t i-t i−t项到第 i − 1 i-1 i−1项。我们只需要考虑一个长度为 t + 1 t+1 t+1的序列满足最后一张牌与猜测结果相同的概率。为了方便计算,我们将同种花色的牌视作互不相同的。
设 g i , j g_{i,j} gi,j表示长度为 i i i,花色最少出现的次数为 j j j的序列个数。但因为同种花色的牌数量有限,所以不能用组合数来求,很难直接计算出 g g g,所以我们考虑背包。
设 f c , i , j f_{c,i,j} fc,i,j表示放了前 c c c种花色,卡牌种数为 i i i,最少出现次数为 j j j的方案数。那么对于每个状态,我们只需枚举下一个颜色的放置个数 p p p,就可以由 f c , i , j f_{c,i,j} fc,i,j转移到 f c + 1 , i + p , min ( i , p ) f_{c+1,i+p,\min(i,p)} fc+1,i+p,min(i,p)。因为同种花色的牌是互不相同的,所以转移系数为 C i + p i × C n i × i ! C_{i+p}^i\times C_n^i\times i! Ci+pi×Cni×i!。
对于 j ≥ 1 j\geq 1 j≥1, g i , j = f 4 , i , j g_{i,j}=f_{4,i,j} gi,j=f4,i,j。而 g i , 0 = ∑ c = 1 3 ∑ j = 1 i / c C 4 c f c , i , j g_{i,0}=\sum\limits_{c=1}^3\sum\limits_{j=1}^{i/c}C_4^cf_{c,i,j} gi,0=c=1∑3j=1∑i/cC4cfc,i,j。设 h i h_i hi表示长度为 i i i的不同抽卡序列的个数,则 h i = ∑ j = 0 n g i , j h_i=\sum\limits_{j=0}^n g_{i,j} hi=j=0∑ngi,j。
在计算答案时,我们只需求出对应的 t t t,然后求出满足猜测的序列的个数,再除以总方案数就能得出猜对的概率。当 i = 1 i=1 i=1时,猜对的概率为 1 4 \dfrac 14 41。最后的答案为 1 4 + ∑ i = 2 4 n ∑ j = 1 t / 4 g t , j × ( n − j ) h t + 1 \dfrac 14+\sum\limits_{i=2}^{4n}\frac{\sum\limits_{j=1}^{t/4}g_{t,j}\times (n-j)}{h_{t+1}} 41+i=2∑4nht+1j=1∑t/4gt,j×(n−j)。
#include
using namespace std;
const int N=2000;
long long ans,jc[2005],ny[2005],h[2005],g[2005][2005],f[5][2005][2005];
long long mod=998244353;
long long mi(long long t,long long v){
if(!v) return 1;
long long re=mi(t,v/2);
re=re*re%mod;
if(v&1) re=re*t%mod;
return re;
}
long long C(int x,int y){
return jc[x]*ny[y]%mod*ny[x-y]%mod;
}
void init(){
jc[0]=1;
for(int i=1;i<=N;i++) jc[i]=jc[i-1]*i%mod;
ny[N]=mi(jc[N],mod-2);
for(int i=N-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;
}
int main()
{
init();
long long n,k;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++) f[1][i][i]=jc[n]*ny[n-i]%mod;
for(int c=1;c<4;c++){
for(int i=c;i<=c*n;i++){
for(int j=1;j<=i/c;j++){
if(f[c][i][j]==0) continue;
for(int p=1;p<=n;p++){
long long tmp=C(i+p,p)*C(n,p)%mod*jc[p]%mod;
f[c+1][i+p][min(j,p)]=(f[c+1][i+p][min(j,p)]+tmp*f[c][i][j]%mod)%mod;
}
}
}
}
for(int i=1;i<=4*n;i++){
for(int j=1;j<=n;j++){
g[i][j]=f[4][i][j];
}
}
for(int c=1;c<=3;c++){
for(int i=1;i<=c*n;i++){
for(int j=1;j<=i/c;j++){
g[i][0]=(g[i][0]+C(4,c)*f[c][i][j]%mod)%mod;
}
}
}
for(int i=1;i<=4*n;i++){
for(int j=0;j<=n;j++){
h[i]=(h[i]+g[i][j])%mod;
}
}
ans=mi(4,mod-2);
for(int i=2;i<=4*n;i++){
long long tmp=0;
int t=min(i-1ll,k);
for(int j=0;j<=t/4;j++){
tmp=(tmp+g[t][j]*(n-j)%mod)%mod;
}
tmp=tmp*mi(h[t+1],mod-2)%mod;
ans=(ans+tmp)%mod;
}
printf("%lld",ans);
return 0;
}