2020.12.20日常总结——概率思维好题

[SHOI2002]百事世界杯之旅 \color{green}{\texttt{[SHOI2002]百事世界杯之旅}} [SHOI2002]百事世界杯之旅

[Problem] \color{blue}{\texttt{[Problem]}} [Problem]

n n n 个等可能的奖品,买一瓶饮料就可以得到一个奖品,求期望下买多少瓶饮料可以获得所有的奖品。

以假分数的形式输出答案。

[Solution] \color{blue}{\texttt{[Solution]}} [Solution]

f i f_i fi 表示期望下买多少瓶饮料可以获得 i i i 中奖品。

考虑如何推导出 f i + 1 f_{i+1} fi+1

  • f i f_{i} fi 推导来:即得了一瓶现在还没有的奖品,有 n − i n \dfrac{n-i}{n} nni 的可能性,所以期望为 n − i n × ( f i + 1 ) \dfrac{n-i}{n} \times \left (f_{i}+1 \right ) nni×(fi+1)
  • f i + 1 f_{i+1} fi+1 推导来:即得到了已有的奖品,有 i + 1 n \dfrac{i+1}{n} ni+1 的可能性,期望为 i + 1 n × ( f i + 1 + 1 ) \dfrac{i+1}{n} \times \left (f_{i+1} +1\right) ni+1×(fi+1+1)

所以, f i + 1 = n − i n × ( f i + 1 ) + i + 1 n × ( f i + 1 + 1 ) f_{i+1}=\dfrac{n-i}{n} \times \left ( f_{i} +1 \right) + \dfrac{i+1}{n} \times \left ( f_{i+1} +1 \right ) fi+1=nni×(fi+1)+ni+1×(fi+1+1)

这个式子看似非常显然,但是有个问题:为什么概率的总和(即可能性的总和)会对于 1 1 1 呢?

f i f_i fi 推导来的是没有错的,只能是从 f i + 1 f_{i+1} fi+1 推导来的错了。但是,错在哪里了呢?

回想一下生活中你买饮料时的经历,当我们凑齐了所有的奖品之后,我们就不会再买饮料了 (除非你很想喝或想再中一次)。这里也一样。

因为我们考虑 f i + 1 f_{i+1} fi+1,所以我们把这 ( i + 1 ) (i+1) (i+1) 种奖品就看作所有的奖品。我们把思维逆过来——即从 ( i + 1 ) (i+1) (i+1) 种奖品中放弃一种奖品。如果我们的统计是对的,那么我们把过程逆过来也应该要得到相同的结论。

我们不断地放走一个奖品,那么总会有一个奖品满足:放弃它之后我们就只有 i i i 种奖品了,我们记它为第 ( i + 1 ) (i+1) (i+1) 种奖品。

于是我们在考虑加入第 ( i + 1 ) (i+1) (i+1) 种奖品的时候,在得到它之前其实我们只有 i i i 种奖品,所以原来的分类方法会产生重复,重复就在第 ( i + 1 ) (i+1) (i+1) 种奖品这里。

既然产生了重复,那么我们把第 ( i + 1 ) (i+1) (i+1) 种奖品算哪里呢?算在 f i f_{i} fi 中,为什么呢?

这么来想:还是那句话,已经得到了 ( i + 1 ) (i+1) (i+1) 种奖品时我们不会再拿奖品,那么在我们拿到了 ( i + 1 ) (i+1) (i+1) 中奖品后,我们再拿这里的奖品就是为了获得第 ( i + 2 ) (i+2) (i+2) 种奖品了(比如你有 4 4 4 种奖品了,那么你再拿这 4 4 4 种奖品中的一个其实是为了拿第 5 5 5 种奖品对吧)。所以我们算在 f i f_{i} fi 中。

于是 f i + 1 = n − i n × ( f i + 1 ) + i n × ( f i + 1 + 1 ) f_{i+1}=\dfrac{n-i}{n} \times \left (f_{i}+1 \right ) + \dfrac{i}{n} \times \left ( f_{i+1}+1 \right ) fi+1=nni×(fi+1)+ni×(fi+1+1)

稍微地移一下项,可以得到: f i + 1 = f i + n n − i f_{i+1}=f_{i} + \dfrac{n}{n-i} fi+1=fi+nin

再加上一点处理分数的知识,就可以 O ( n × log ⁡ n ) O(n \times \log n) O(n×logn) 解决了本题(为什么有个 log ⁡ \log log,因为要求 gcd ⁡ \gcd gcd)。

[code] \color{blue}{\texttt{[code]}} [code]

typedef long long ll;
inline ll gcd(ll a,ll b){
	return b==0?a:gcd(b,a%b);
}
inline int digit_num(ll t){
	register int ret=0;
	while (t){ret++;t/=10;}
	return ret;
}
ll t[35],f[35],g[35];int n;
int main(){
	cin>>n;f[1]=1;g[1]=1;
	for(int i=1;i<n;i++){
		g[i+1]=g[i]*(n-i);
		f[i+1]=f[i]*(n-i)+g[i]*n;
		int tmp=gcd(g[i+1],f[i+1]);
		f[i+1]/=tmp;g[i+1]/=tmp;
		t[i+1]=t[i]+f[i+1]/g[i+1];
		f[i+1]%=g[i+1];
	}
	if (f[n]==0) printf("%lld",t[n]);
	else{
		int num=digit_num(t[n]);
		int sum=digit_num(g[n]);
		for(int i=1;i<=num;i++)
			printf(" ");
		printf("%lld\n",f[n]);
		printf("%lld",t[n]);
		for(int i=1;i<=sum;i++)
			printf("-");
		printf("\n");//注意换行 
		for(int i=1;i<=num;i++)
			printf(" ");
		printf("%lld",g[n]);
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值