CF1765C Card Guessing
Posted tanjunming2020
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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/cC_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/4g_t,j\\times (n-j)h_t+1 41+i=2∑4nht+1j=1∑t/4gt,j×(n−j)。
code
#include<bits/stdc++.h>
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;
rst003_guessing game
创建项目
[[email protected] test]# cargo new guessing_game
Created binary (application) `guessing_game` package
[[email protected] test]# cd guessing_game
[[email protected] guessing_game]# ls
Cargo.toml src
[[email protected] guessing_game]# cat Cargo.toml
[package]
name = "guessing_game"
version = "0.1.0"
authors = ["tanpf <[email protected]>"]
edition = "2018"
[dependencies]
the main
function is the entry point into the program
# vim src/main.rs
use std::io;
fn main() {
println!("Guess the number!");
println!("Please input your guess.");
let mut guess = String::new();
io::stdin().read_line(&mut guess)
.expect("Failed to read line");
println!("You guessed: {}", guess);
}
println!
is a macro that prints a string to the screen, then create a place to store the user input
以上是关于CF1765C Card Guessing的主要内容,如果未能解决你的问题,请参考以下文章