[期望DP]彩色圆环

彩色圆环

感谢名单
十分感谢 JA_Ma 为我讲解了 \(T1\) 的 期望DP 的思想和推论。
十分感谢 SSL_LYF 为我解答了 \(T1\) 的 期望DP 的概率的大小问题。
十分感谢 SSL_WJ 为我讲解了 高斯消元 的一些判断及一些基础知识。
(排名不分先后)

正文

这道题已经告诉你是 期望DP 了, 主要是 状态转移方程 的推导和 最后的 ans 进行求值

我们先预处理出每个区间的概率 \(g_i\) 以便于状态转移时使用。
再解释一下 \(f_{i, 1/0}\) 表示的是什么
其实表示的就是在前 \(i\) 个数中, 第 \(i\) 个数于首尾交界点是(1)否(0)相同的期望值。

然后我们就考虑怎么转移。
我们把这个环切成切成一条链, 我们期望一个区间 [j, i] 都是同一个颜色的, 然后我们就以 \(f_{j, 0/1}\) 进行转移。 我们只需将转移的期望乘目前区间的贡献再乘上这个区间都是同色的概率再乘于 \(m\) 种颜色中颜色的概率

然后我们进行分类讨论。
我们先考虑当 \(1\) 点与首尾交界点(我们人为添加的点, 这个点并不存在于链当中)不同色的情况。
这个情况我们还可以分两种类, 就是 \(i\) 点和这个 \(1\) 点的颜色是否相同两个可能
可以得出转移方程:

\[f[i][0] += f[j][0] * p[i - j] * (i - j) * (m - 2) / m; \]

这个是色不同的, 因为总共有 \(m\) 个色, 所以就是 可选颜色数/m, 问题就是求可选色的数量。这里应为色不同, 所以就只有 \(m-1\) 中色可选, 又因区间 [j, i] 与 \(j-1\)前的区间的色也不一样(色一样的话这个区间就不之这么大了), 所以可选色只有 \(m-2\).
对于概率是 \(p_{i-j}\) 是因为他这个区间的色是相同的, 然后他的长度就为 \(i - j\), 所以这个区间他颜色相同的几率就是 \(p_{i - j}\), 而 \(i - j\) 就是这个区间的贡献

\[f[i][0] += f[j][1] * p[i - j] * (i - j) * (m - 1) / m; \]

这个和上面的情况极为相近, 但是因为他 \(i\) 点和这个 \(1\) 点的颜色是相同的, 就有了些变化。
可选颜色就是被 \(j-1\) 前的区间占了一个, 所以就还有 \(m-1\)个颜色可选, 因为 \(i\) 点和这个 \(1\) 点的颜色相同, 所以是从 \(f_{j, 1}\) 状态转移过来的。

然后我们考虑最后一种可能了, 就是 \(1\) 点与首尾交界点同色的情况。
因为期望还是转移的期望乘目前区间的贡献再乘上这个区间都是同色的概率再乘于 \(m\) 种颜色中颜色的概率, 所以就和前一个也是差不多, 其实就是

\[f[i][1] += f[j][0] * p[i - j] * (i - j) / m; \]

不同就是因为他是同色, 所以就不用考虑占色的情况

然后就是重头戏, 计算答案了。
首先, 我们可以 \(O(1)\) 可以过 \(n\) 的情况, 应为就一个色, 所以就是贡献 \(n~*~p_n\) 的情况
然后就是 1~n-1 的答案计算了
首先是他计算的这个期望 \(f_{i, 0}\) 然后就是 他这个出现的几率, 然后就是他这个区间是有 \(n - i\) 个点, 每个点是都可以产生这么多的贡献的。 还有, 就是这个区间他是可以每一个节点都作为一个断点(即将这个环断成链的点), 所以还是要乘上 \(n - i\) 的, 所以可以得到

\[ans += \left\{\begin{matrix} n~~*~~p[n]\\ \prod_{n-1}^{i = 1}~~f_{i,0}~~* ~~p_{n~~-~~i}~~*~~(n-i)~~*~~(n-i) \end{matrix}\right.\]

Code

#include <bits/stdc++.h>
#define N 205
using namespace std;

int n, m;
double ans;
double f[N][2], p[N];

int main ()
{
	scanf ("%d%d", &n, &m);
	p[1] = 1.0;
	f[0][1] = 1;
	for (int i = 2; i <= n; ++ i)
	 p[i] = p[i - 1] * (1.0 / m);
	for (int i = 1; i <= n; ++ i)
	{
		for (int j = 0; j < i; ++ j)
		{
			f[i][0] += f[j][0] * p[i - j] * (i - j) * (m - 2) / m;
			f[i][0] += f[j][1] * p[i - j] * (i - j) * (m - 1) / m;
			/*不同情况分割线*/
			f[i][1] += f[j][0] * p[i - j] * (i - j) / m;
		}	
	} 
	ans = n * p[n];
	for (int i = 1; i < n; ++ i)
	{
		ans += f[i][0] * p[n - i] * (n - i) * (n - i);
	}
	printf ("%.7lf", ans);
	return 0;
} 
posted @ 2021-07-15 22:38  unknown_future  阅读(161)  评论(0编辑  收藏  举报