\(\rm upd\):是我假了...这题没有爆精...大家要记得这道题是相对误差\(10^{-6}\)...感谢@foreverlasting的指正。

题是好题,可是标算爆精是怎么回事...要写的和标算一毛一样才能过。

各位要写的话过了前5个点就当过了吧...

题意

你有\(n\)张牌,每张牌上有一个\(1\sim m\)的点数,你每次随机选出两张不同的牌\(A\)和\(B\),并将\(A\)的点数变为\(B\)的点数。求将所有牌的点数变成一样的期望步数。用\(double\)输出。\(n\leq 10^9\),\(m\leq 10^5\)。

题解

那首先有个挺显然的想法是枚举最终变成了哪种牌,那么所有牌就变成了是这种牌与不是这种牌两类。我们这么计算这种情况的贡献:

假如若干步以后,是这种牌的数量变为\(0\),则这种情况的贡献为\(0\)。
否则,若干步以后是这种牌的数量变为\(n\),则这种情况的贡献为\(发生的概率*步数\)。

那么只要把每种牌的这个答案加起来就好了。

现在我们要解决的问题是:有两种牌,第一种有\(i\)张,第二种有\(n-i\)张,问最终全变为第一种牌的贡献。

很显然当\(n\)固定的时候,答案只和\(i\)有关。于是我们将其记为\(f_i\)。

在计算\(f_i\)之前,我们先来计算辅助数组\(g\)。其中\(g_i\)表示有两种牌,第一种有\(i\)张,第二种有\(n-i\)张,问最终全变为第一种牌的概率

怎么求\(g_i\)呢?首先边界条件有\(g_0=0\),\(g_n=1\),再来考虑一般的情况。

我们来考虑一下第一次对牌数有影响的操作。假如\(A\)是第一种牌,\(B\)是第二种牌,那么第一种牌数\(-1\);假如\(A\)是第二种牌,\(B\)是第一种牌,那么第一种牌数\(+1\)。显然这两种情况的方案数是一样的,于是可以得出\(i\)会等概率变成\(i-1\)或\(i+1\),于是就可以得到一个简单的式子:

\[g_i=\frac{1}{2}(g_{i-1}+g_{i+1})\]

于是移项得到:

\[g_{i+1}=2*g_i-g_{i-1}\]

可以发现每一项都依赖前两项,于是我们设\(g_1=x\),则可计算出\(g_2=2*x\),\(g_3=3*x\),\(\dots\),那么显然我们可以猜想\(g_i=i*x\),可以通过归纳法证明其是成立的。

于是得到\(g_n=n*x=1\),解得\(x=\frac{1}{n}\)。

因此当第一种牌数为\(i\)时,最终全变成第一种牌的概率为\(\frac{i}{n}\)。

现在来考虑求\(f_i\),边界条件有\(f_0=0\),\(f_n=0\),一般情况显然还是可以归纳成\(f_{i-1}\)和\(f_{i+1}\)的情况。不过这次还要额外考虑一些事情:

以变成\(i-1\)为例,首先我们枚举在几步以后变成\(i-1\)。设没有影响的操作发生概率为\(p\),使\(i\)变为\(i-1\)的操作发生概率为\(q\)。则可得到期望额外花费的步数为:

\[\sum_{j\geq 0}\Big((j+1)*p^j*q\Big)\]

整理得其为\(\frac{q}{(1-p)^2}\)。

还要注意的是由于规约到\(i-1\)的情况后成功的概率是\(\frac{i-1}{n}\),而失败的贡献是\(0\),因此期望步数只有\(\frac{i-1}{n}\)是有效的,贡献为\(\frac{q}{(1-p)^2}*\frac{i-1}{n}\)。

对于\(i+1\)的情况,\(p\)和\(q\)是一样的,因此贡献为\(\frac{q}{(1-p)^2}*\frac{i+1}{n}\)。两者相加为\(\frac{q}{(1-p)^2}*\frac{2*i}{n}\)。

可以计算得\(1-p=\frac{2*i*(n-i)}{n*(n-1)}\),\(q=\frac{i*(n-i)}{n*(n-1)}\)。于是原式可化简为:

\[\frac{n-1}{2*(n-i)}\]

因此可以得到:

\[f_i=\frac{1}{2}(f_{i-1}+f_{i+1})+\frac{n-1}{2*(n-i)}\]

移项可得:

\[f_{i+1}=2*f_i-f_{i-1}-\frac{n-1}{n-i}\]

依然设\(f_1=x\),则\(f_2=2*x-\frac{n-1}{n-1}\),\(f_3=3*x-2*\frac{n-1}{n-1}-\frac{n-1}{n-2}\),\(\dots\),依然可以通过观察和归纳法证明:

\[f_i=i*x-\sum_{j=1}^{i-1}\Big((i-j)*\frac{n-1}{n-j}\Big)\]

那么对于\(f_n\):

\[f_n=n*x-\sum_{j=1}^{n-1}\Big((n-j)*\frac{n-1}{n-j}\Big)=0\]

可解得\(x=\frac{(n-1)*(n-1)}{n}\)。

于是继续对\(f_i\)的式子进行化简:

\[f_i=i*\frac{(n-1)*(n-1)}{n}-i*(n-1)*\Big(\sum_{j=1}^{i-1}\frac{1}{n-j}\Big)+(n-1)*\Big(\sum_{j=1}^{i-1}\frac{j}{n-j}\Big)\]

我们设\(H_i\)为调和数,即\(H_i=\sum_{j=1}^{i}\frac{1}{j}\),则第二项等于:

\[-i*(n-1)*(H_{n-1}-H_{n-i})\]

继续推导第三项:

\[(n-1)*\Big(\sum_{j=1}^{i-1}\frac{j}{n-j}\Big)\]

\[(n-1)*\Big(\sum_{j=1}^{i-1}\big(\frac{n}{n-j}-1\big)\Big)\]

\[(n-1)*n*\Big(\sum_{j=1}^{i-1}\frac{1}{n-j}\Big)-(n-1)*(i-1)\]

\[(n-1)*n*(H_{n-1}-H_{n-i})-(n-1)*(i-1)\]

将三项合并,最终得到:

\[f_i=i*\frac{(n-1)*(n-1)}{n}+(n-1)*(n-i)*(H_{n-1}-H_{n-i})-(n-1)*(i-1)\]

那么问题来了,\(n\)那么大,\(H_n\)怎么求呢?标算的做法是将小的调和数预处理,大的用\(H_x\simeq \ln x+\gamma\)来近似,其中\(\gamma\)为欧拉常数。但是不知道为啥标算的\(\gamma\)取的是\(0.57\)...不过实测下来就算预处理前\(2^{20}\)的调和数以及用较精确的欧拉常数后面的误差也在\(10^{-7}\)左右...再乘以一个大常数算答案精度堪忧。

这里再提供一个精度靠谱复杂度也有保证的做法。注意到答案中计算贡献的调和数其实类似于倒数的后缀和,因此\(i\)较小的时候显然可以预处理。可以设一个阈值\(T\),预处理前\(T\)个后缀和,剩下的数不会超过\(\frac{n}{T}\)个,可以用分段打表暴力处理。由于查询量不是很大,打表的间隔可以取大一点减少代码长度。

还有由于答案有点大最好开\(long\ double\)或者自己写精度更高的类型...不过反正标算都爆精了这些好像也是后话了。这么好的题为什么不取模呢,用第二种做法就很靠谱了。

LOJ#6118 鬼牌的更多相关文章

  1. [loj6118]鬼牌

    枚举最终所有牌的大小$i$,对于最终所有牌大小都为$i$的情况,令其贡献为步数,否则令其贡献为0,记$F$为期望贡献(即所有情况概率*贡献之和),答案即为$\sum_{i=1}^{m}F$ 显然,$F ...

  2. UOJ147 斗地主

    题目描述 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54张牌来进行的扑克牌游戏.在斗地主中,牌的大小关 系根据牌的数码表示如下:3<4&l ...

  3. UOJ 151 斗地主“加强”版

    #151. [NOIP2015]斗地主“加强”版 统计 描述 提交 自定义测试 本题开放Hack 牛牛最近迷上了一种叫斗地主的扑克游戏.斗地主是一种使用黑桃.红心.梅花.方片的A到K加上大小王的共54 ...

  4. FZU 2216 The Longest Straight(最长直道)

    Description 题目描述 ZB is playing a card game where the goal is to make straights. Each card in the dec ...

  5. Pandas python

    原文:  https://github.com/catalystfrank/Python4DataScience.CH   和大熊猫们(Pandas)一起游戏吧!   Pandas是Python的一个 ...

  6. Python数据分析入门之pandas基础总结

    Pandas--"大熊猫"基础 Series Series: pandas的长枪(数据表中的一列或一行,观测向量,一维数组...) Series1 = pd.Series(np.r ...

  7. 扑克牌(cards)

    扑克牌 思路 这题也是二分!! 我们二分有几套牌,然后再去检验是否符合,至于怎么想到的,不要问我,我也不知道 那么我们主要解决的就是check函数 我们将二分的套数和每种牌的数量进行比较,如果该种牌的 ...

  8. Codeforces 1392H - ZS Shuffles Cards(DP+打表找规律)

    Codeforces 题面传送门 & 洛谷题面传送门 真·两天前刚做过这场的 I 题,今天模拟赛就考了这场的 H 题,我怕不是预言带师 提供一种奇怪的做法,来自于同机房神仙们,该做法不需要 M ...

  9. Solution -「CF 1392H」ZS Shuffles Cards

    \(\mathcal{Description}\)   Link.   打乱的 \(n\) 张编号 \(1\sim n\) 的数字排和 \(m\) 张鬼牌.随机抽牌,若抽到数字,将数字加入集合 \(S ...

随机推荐

  1. Java 中long类型转换成为int类型时可能会出错的地方

    那计算两个日期之间间隔的天数为例来说明这个问题. 下面是计算日期间隔天数的简单算法(主要出错的地方为红色标注的地方): public int getDay(String startDate, Stri ...

  2. bat输出重定向

    重定向符号主要有:>,>>,<,>&,<&和|,而本文只讨论前五个. 第一节 首先从一个经典问题开始,“1>nul 2>nul”的意思是 ...

  3. 生成定长随机数-可做3des密钥

    3DES加解密需要密钥支持,要求为8的倍数,一般会使用32位的字母数字随机字符串作为密钥. 下面这个工具类,可用做key值的生成,详见下方代码: package test; import java.u ...

  4. 【CobaltStrike】CobaltStrike简介与使用

    CobaltStrike简介与使用 0x00 简介 1. 什么是CobaltStrike?可以用来做什么? CobatStrike是一款基于java编写的全平台多方协同后渗透攻击框架.CobaltSt ...

  5. 20155301 Exp7 网络欺诈防范

    20155301 Exp7 网络欺诈防范 1.基础问题回答 (1)通常在什么场景下容易受到DNS spoof攻击 (2)在日常生活工作中如何防范以上两攻击方法 2.实践过程记录 简单应用SET工具建立 ...

  6. TMS320VC5509使用nof flash AM29LV400

    1. 硬件接口如下,其中nor flash的使用方法,写的时候和NAND FLASH是一样的,读的时候和DRAM是一样的 2. 看下擦除指令和编程指令 3. 代码如下 #include <csl ...

  7. C++学习之从C到C++

    头文件的包含 包含头文件可以不加.h结尾,如iostream,一些常用的头文件在引用时可以不加.h后缀,并在开头增加c,如: #include <cstdio> #include < ...

  8. Arcgis安装要素

    1. ArcGIS安装过程中需将用户名改为计算机名,该计算机名称时需要新建对话框. 2. ArcGIS Server安装过程中要设置ArcGISWebServices用户的读写权限,即设置ASP.NE ...

  9. Scrapy爬虫入门实例

    网上关于Scracpy的讲述已经非常丰富了,而且还有大神翻译的官方文档,我就不重复造轮子了,自己写了一个小爬虫,遇到不少坑,也学到不少东西,在这里给大家分享一下,自己也做个备忘录. 主要功能就是爬取c ...

  10. 微信小程序实现各种特效实例

    写在前面 最近在负责一个微信小程序的前端以及前后端接口的对接的项目,整体上所有页面的布局我都已经搭建完成,里面有一些常用的特效,总结一下,希望对大家和我都能有所帮助 实例1:滚动tab选项卡 先看一下 ...