CF1765C Card Guessing

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 1n500 1 ≤ k ≤ 4 × n 1\leq k\leq 4\times n 1k4×n


题解

根据期望的线性性,期望猜对的次数等于每次猜对的概率之和。若当前是第 i i i次猜测,设 t = min ⁡ ( k , i − 1 ) t=\min(k,i-1) t=min(k,i1),那么是否猜对只取决于第 i − t i-t it项到第 i − 1 i-1 i1项。我们只需要考虑一个长度为 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 j1 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=13j=1i/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=0ngi,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=24nht+1j=1t/4gt,j×(nj)

code

#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;
}

你可能感兴趣的:(题解,c++,题解)