\(\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框架:hibernate(四)

    一.绑定本地session 原理:之前connection实现事务一个道理,2种方法:1.变量下传.2.因为servlet是单线程,和本地当前线程绑定. 配置: 1)配置核心配置文件hibernate ...

  2. liMarquee – jQuery无缝滚动插件(制作跑马灯效果)

    liMarquee 是一款基于 jQuery 的无缝滚动插件,类似于 HTML 的 marquee 标签,但比 marquee 更强大.它可以应用于任何 Web 元素,包括文字.图像.表格.表单等元素 ...

  3. Failed to fetch URL https://dl-ssl.google.com/android/repository/addons_list-2.xml

    解决方法来源:http://www.cnblogs.com/kaka-bing/archive/2012/10/31/2747490.html 问题描述: 使用Android SDK Manager检 ...

  4. day51

    JS基础操作 一.分支结构 1.if语句 if 基础语法 if (条件表达式) { 代码块; } // 当条件表达式结果为true,会执行代码块:反之不执行 // 条件表达式可以为普通表达式 // 0 ...

  5. Altium 拼板方法以及 注意的 地方

    1.修改软件设置, 即工具→优先选项→覆铜重建 对号去掉,如下,否则 拼板复制 覆铜 会变形导致拼板错误!!! 2.拼板方法,Ctrl+A全部复制(不要漏掉),选择特殊粘贴的方式,快捷键 E→A  去 ...

  6. SQL Server聚合函数与聚合开窗函数

    以下面这个表的数据作为示例. 什么是聚合函数? 聚合函数:聚合函数就是对一组值进行计算后返回单个值(即分组).聚合函数在计算时都会忽略空值(null). 所有的聚合函数均为确定性函数.即任何时候使用一 ...

  7. .NET Core 对象到字节数组的序列化和反序列化

    .NET Core中利用MemoryStream和BinaryFormatter可以实现对象到字节数组的序列化和反序列化: 定义ObjectSerializer类,实现对象到字节数组的序列化和反序列化 ...

  8. ASP.NET Core中,UseDeveloperExceptionPage扩展方法会吃掉异常

    在ASP.NET Core中Startup类的Configure方法中,有一个扩展方法叫UseDeveloperExceptionPage,如下所示: // This method gets call ...

  9. Segment Tree Beats 区间最值问题

    Segment Tree Beats 区间最值问题 线段树一类特殊技巧! 引出:CF671C Ultimate Weirdness of an Array 其实是考试题,改题的时候并不会区间取最值,区 ...

  10. ccf201703-1分蛋糕

    问题描述 小明今天生日,他有n块蛋糕要分给朋友们吃,这n块蛋糕(编号为1到n)的重量分别为a1, a2, …, an.小明想分给每个朋友至少重量为k的蛋糕.小明的朋友们已经排好队准备领蛋糕,对于每个朋 ...