[loj6118]鬼牌
枚举最终所有牌的大小$i$,对于最终所有牌大小都为$i$的情况,令其贡献为步数,否则令其贡献为0,记$F$为期望贡献(即所有情况概率*贡献之和),答案即为$\sum_{i=1}^{m}F$
显然,$F$仅取决于牌的数量,定义$F_{i}$表示恰有$i$张牌的期望贡献,那么答案即为$\sum_{i=1}^{m}F_{a_{i}}$
在求$F_{i}$的转移之前,先定义$P_{i}$为贡献为步数的情况的概率,关于$P_{i}$的转移,不难得到
$$
\begin{cases}P_{0}=0,P_{n}=1\\P_{i}=\frac{P_{i-1}+P_{i+1}}{2}&(1\le i<n)\end{cases}
$$
这是一个经典的问题,通项为$P_{i}=\frac{i}{n}$
考虑$F_{i}$的转移,即为
$$
\begin{cases}F_{0}=F_{n}=0\\F_{i}=\frac{i(n-i)}{n(n-1)}(F_{i-1}+F_{i+1}+\frac{2i}{n})+(1-\frac{2i(n-i)}{n(n-1)})(F_{i}+\frac{i}{n})&(1\le i<n)\end{cases}
$$
(注意每一次步数并不是+1,而是加上目标状态的$P_{i}$,因为只有$P_{i}$的概率这步有贡献)
将其化简,即为
$$
\begin{cases}F_{0}=F_{n}=0\\F_{i+1}=2F_{i}-F_{i-1}-\frac{n-1}{n-i}&(1\le i<n)\end{cases}
$$
将其差分,即令$G_{i}=F_{i+1}-F_{i}$,那么
$$
\begin{cases}G_{0}=F_{1},\sum_{i=0}^{n-1}G_{i}=0\\G_{i}=G_{i-1}-\frac{n-1}{n-i}&(1\le i<n)\end{cases}
$$
将第2个式子不断迭代,即可得$G_{i}=F_{1}-\sum_{j=1}^{i}\frac{n-1}{n-j}$,那么
$$
\sum_{i=0}^{n-1}G_{i}=nF_{1}-\sum_{i=0}^{n-1}\sum_{j=1}^{i}\frac{n-1}{n-j}=nF_{1}-\sum_{j=1}^{n-1}\frac{n-1}{n-j}(n-j)=nF_{1}-(n-1)^{2}=0
$$
解得$F_{1}=\frac{(n-1)^{2}}{n}$,进而可得
$$
F_{i}=\sum_{j=0}^{i-1}G_{j}=iF_{1}-\sum_{j=1}^{i-1}\frac{n-1}{n-j}(i-j)=\frac{i(n-1)^{2}}{n}-(i-1)(n-1)+(n-i)(n-1)\sum_{j=n-i+1}^{n-1}\frac{1}{j}
$$
(最后一个变化是将$i-j$变形为$(n-j)-(n-i)$,再根据分配律展开即可)
关于最后一项,令$H_{n}=\sum_{i=1}^{n}\frac{1}{i}$,即$H_{n}-H_{n-i}$,关于$H_{n}$为调和级数,用$H_{n}=\ln n+C$来模拟即可(较小范围预处理,$C$使用0.5772即可,当然还可以分块打表)
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 10000005 4 #define C 0.5772 5 #define ld long double 6 int n,m,x; 7 ld nn,ans,h[N]; 8 ld H(int n){ 9 if (n<N)return h[n]; 10 return log(n)+C; 11 } 12 ld calc(int k){ 13 return k*(nn-1)*(nn-1)/nn-(k-1)*(nn-1)+(nn-k)*(nn-1)*(H(n-1)-H(n-k)); 14 } 15 int main(){ 16 for(int i=1;i<N;i++)h[i]=h[i-1]+(ld)1/i; 17 scanf("%d%d",&n,&m); 18 nn=n; 19 for(int i=1;i<=m;i++){ 20 scanf("%d",&x); 21 ans+=calc(x); 22 } 23 printf("%.7Lf",ans); 24 }