CF1392 H. ZS Shuffles Cards
题目叙述
有 张正常的牌(不同的)和 张鬼牌,每次可以抽出一张牌,如果是鬼牌则将所有抽到的牌都放回去。如果是正常的牌则收下。问期望多少次能够将所有的正常牌都抽一遍。
题解
方法一
设 表示现在抽到过 张正常的牌,桌子上有 张牌和手里的重合,期望还需要多少次。
转移是容易的:
考虑差分。 会得到一个算式。然后可以发现这是一个关于他们差分的递推式。
而我们发现 构成一个等差数列。根据这个关于 的递推式,可以发现 与 的差也是一个固定的数,而且就是 。
就此就可以通过 推出 的值。
再根据 的递推式算出 到 的递推,就可以算出答案了。
方法二
可以发现两次抽出鬼牌之间的期望次数是相等的,都是 次。
所以其实只需要求出最后一次抽出的鬼牌是第几张抽出的即可。
设 表示第 张牌抽出之后第一张不是鬼牌的牌是抽出的第几次抽出鬼牌。
所以我们要求的就是 。
考虑 容斥, 。
其中 为所有牌组成的集合。
的含义就是在抽出这一张牌之前,抽出的鬼牌数量+1。
可以发现这时候抽出一张需要的牌的概率是固定的,即 ,因此期望步数就是 。再套上那个算式计算一下就好了,具体就不细说了。
总结
- 可以先猜测一些二维递推比较简单之类的。这个就每行都是一个等差数列。
- 另外对于这种递推式可以尝试差分一下。会有一些效果。
- 如果达成一件事情的概率在变化(比如这题里因为牌数变化的原因导致的问题),那么可以考虑 容斥把变化的转化为不变的。
代码
#include <cstdio>
#include <iostream>
#define macro_expand(x) #x
#define print_macro(x) printf("%s\n",macro_expand(x))
#define FOR(i,l,r) for(int i=(l);i<=(r);++i)
#define ROF(i,r,l) for(int i=(r);i>=(l);--i)
using namespace std;
typedef long long LL;
const int Mod=998244353;
int add(int &x,int y){return ((x+=y)>=Mod)?(x-=Mod):x;}
int dec(int &x,int y){return ((x-=y)<0)?(x+=Mod):x;}
int ad(int x,int y){return ((x+y)>=Mod)?(x+y-Mod):(x+y);}
int dc(int x,int y){return ((x-y)<0)?(x-y+Mod):(x-y);}
int ml(int x,int y){return (LL)x*y%Mod;}
int ksm(int x,int y){
int ret=1;
for(;y;y>>=1,x=ml(x,x))if(y&1)ret=ml(ret,x);
return ret;
}
int N,M;
int main(){
// freopen("h.in","r",stdin);
// freopen(".out","w",stdout);
scanf("%d%d",&N,&M);
int ans=0;
for(int i=0;i<=N-1;++i){
int tmp=ad(ml(M,N),ad(ml(M,M),ad(N-i,M)));
add(ans,ml(tmp,ksm(ml(M+1,N-i),Mod-2)));
}
printf("%d\n",ad(ans,1));
// fclose(stdin);
// fclose(stdout);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现