[The 2019 Asia Yinchuan First Round Online Programming] D Take Your Seat

也许更好的阅读体验

D e s c r i p t i o n \mathcal{Description} Description

原题链接

题目大意

该题目有两个问题

  • T a s k   1 Task\ 1 Task 1,有 n n n个人 n n n个座位,每个人都有一个对应的座位,每个人排队进入去坐座位,小 A A A第一个,然而小 A A A忘记了自己的位置,于是他进去后自己随便坐了一个位置,之后的人进来后若发现自己的位置已经被人坐了,那么他就随便坐一个没人坐的位置,如果自己的位置没有被人坐,那么就会坐自己的位置,问最后一个进来的人坐到自己的位置概率是多少

  • T a s k   2 Task\ 2 Task 2,有 m m m个人 m m m个座位,该问题与上面问题差不多,但是每个人并不会排队进去,而是随机的进入,即进入的顺序随机的(包括小 A A A的进入时间),仍然问最后一个进来的人坐到自己的位置的概率是多少

复杂度要求在 O ( n 3 ) O(n^3) O(n3)以内
实际上只要 O ( 1 ) O(1) O(1)

S o l u t i o n \mathcal{Solution} Solution

这题有点考思维,博主想了很久(博主太蒻了),所以会写一些心得,在引用里面,只想知道题解可以跳过
主要是考逆向思维,以及一个问题的转化

不要怕概率这个玩意,尽量想办法避开它,或者只用最简单的概率计算

考虑递推

想了很久如何正着推,但是不知道某个人进来时是否可以坐座位,设了很多方程,都是找不到转移或者错误的转移

一般递推都会是可以将某一个状态变成另一个状态
所以我们要找到什么样的状态是有联系的

  • T a s k   1 Task\ 1 Task 1

    一直想找到一种方法可以考虑到一个座位是否被坐,博主突然发现了一个性质

    我们知道,当小 A A A坐在了第 x x x个进来的人的位置,那么第 2 2 2 x − 1 x-1 x1个人进来时都是直接坐在自己座位上
    这条性质十分显然也十分简单,可是却很容易将其忽视

    博主忽视了1个多小时…

    另外,小 A A A坐在任何一个位置的概率都是 1 n \frac{1}{n} n1
    于是我们可以利用这样的两个性质,开始递推
    我们不认为小 A A A是忘记了自己的座位,而是不知道自己的座位

    f [ i ] f[i] f[i]表示有 i i i个人时,第一个人不知道自己座位(即第一个人会乱坐)的答案
    当小 A A A坐在了自己的座位上时,之后最后一个人坐在自己座位的概率为 100 % 100\% 100%
    当小 A A A坐了第 j j j个人的座位时,当第 j j j个人来找座位时,我们可以认为原本小 A A A的座位是他的座位,而他不知道
    因为当他坐在小 A A A的座位上时,对后面上来的人都没有影响了
    这样,若小 A A A坐了 j j j号座位,当 j j j来找座位时,相当于是考虑原来的问题,只不过 n n n变成了 n − j + 1 n-j+1 nj+1
    于是我们得到了这样的递推式
    f [ i ] = 1 i ∑ j = 1 i − 1 f [ j ] \begin{aligned}f[i]=\frac{1}{i}\sum_{j=1}^{i-1}f[j]\end{aligned} f[i]=i1j=1i1f[j]
    初值 f [ 1 ] = 1 f[1]=1 f[1]=1
    上面这个式子可以记一下前缀和然后就可以 O ( 1 ) O(1) O(1)转移了

    然后博主发现从 2 2 2开始,答案都是 1 2 \frac{1}{2} 21

  • T a s k   2 Task\ 2 Task 2
    由于是完全随机的顺序,所以没有了上面那个性质

    在想出来 T a s k   1 Task\ 1 Task 1的做法后,博主坚信一定是递推,但是又想了一会没想出来
    在内心坚定自己时欧皇的情况下,博主毅然蒙了两个结论提交了程序,于是博主就多了两个罚时…
    因为已经想出来第一问,博主舍不得,于是博主就继续肝了一会儿,又有了一个想法

    仍然是考虑递推,受到 T a s k   1 Task\ 1 Task 1的启发,所以仍然按照这个思维模式
    因为是随机顺序,所以小 A A A是第几个来坐座位的概率都是 1 m \frac{1}{m} m1
    f [ i ] f[i] f[i]表示有 i i i个人的答案
    因为不知道座位是一种特殊的状态,所以我们仍然对它下手
    考虑小 A A A是第 j j j个来坐座位的人
    这样前 j − 1 j-1 j1个人都是坐在自己座位上
    于是现在要考虑的就是有 i − j + 1 i-j+1 ij+1个人,小 A A A第一个来坐座位,剩下的人是随机来坐座位的情况
    g [ i ] g[i] g[i]表示有 i i i个人,小 A A A第一个来坐座位,剩下的人是随机来坐座位,最后一个人坐到自己座位上的答案
    然后我们枚举小 A A A是第几个
    得到这样的递推式
    f [ i ] = 1 i ∑ j = 1 i g [ i ] \begin{aligned}f[i]=\frac{1}{i}\sum_{j=1}^{i}g[i]\end{aligned} f[i]=i1j=1ig[i]
    于是现在就是要想办法求 g g g了,终于把问题转化为一个感jio简单些的问题了

    考虑求 g [ i ] g[i] g[i],我们仍然按照上面的思维模式,考虑小 A A A坐在了第 j j j个来选座位的人的座位
    因为是随机顺序,所以小 A A A随便坐一个位置,其是第 j j j j j j任取)个上来的人的座位的概率仍然是 1 i \frac{1}{i} i1
    于是,在 j j j前面的人都坐自己的位置,从 j j j开始,又是一个 i − j + 1 i-j+1 ij+1个人的问题,当然,别忘了坐在自己坐
    所以得到 g g g的递推式
    g [ i ] = 1 i ∑ j = 1 i − 1 g [ i ] \begin{aligned}g[i]=\frac{1}{i}\sum_{j=1}^{i-1}g[i]\end{aligned} g[i]=i1j=1i1g[i]

    诶,这个和 T a s k   1 Task\ 1 Task 1 f f f是一样的…

    于是问题就得到了解决

    真是可喜可贺可喜可贺…

噢,这还只是 O ( n ) O(n) O(n)是吧
然后我们经过打表发现
对于 T a s k   1 Task\ 1 Task 1
f [ 1 ] = 1 , f [ n ] = 0.5 ( n > 1 ) f[1]=1,f[n]=0.5(n>1) f[1]=1,f[n]=0.5(n>1)
然后对于 T a s k   2 Task\ 2 Task 2
g [ m ] = m + 1 2 m g[m]=\frac{m+1}{2m} g[m]=2mm+1

C o d e \mathcal{Code} Code

这里仍然给了 f , g f,g f,g的递推(以免有不太明白的地方),但是直接用上面的结论 O ( 1 ) O(1) O(1)输出的

/*******************************
Author:Morning_Glory
LANG:C++
Created Time:2019年08月31日 星期六 15时45分43秒
*******************************/
#include <cstdio>
#include <fstream>
using namespace std;
const int maxn = 55;
const int mx = 50;
int T,n,m;
double sum;
double f[maxn],g[maxn];
void init ()
{
	sum=g[1]=f[1]=1,f[2]=1.0/2.0;
	for (int i=2;i<=mx;++i)	f[i]=1.0/i*sum,sum+=f[i],g[i]=sum/(double)i;
}
int main()
{
	scanf("%d",&T);
	init();
	for (int t=1;t<=T;++t){
		scanf("%d%d",&n,&m);
		printf("Case #%d: %.6lf %.6lf\n",t,n>1?0.5:1,(double)(m+1)/(double)(2.0*m));
	}
	return 0;
}

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值