[指望DP][紀中]【2010集訓隊出題】彩色圓環

彩色圓環

感謝名單
十分感謝 JA_Ma 爲我講解了 \(T1\) 的 指望DP 的思想和推論。
十分感謝 SSL_LYF 爲我解答了 \(T1\) 的 指望DP 的機率的大小問題。
十分感謝 SSL_WJ 爲我講解了 高斯消元 的一些判斷及一些基礎知識。
(排名不分前後)c++

正文

GMOJ \(link\) spa

這道題已經告訴你是 指望DP 了, 主要是 狀態轉移方程 的推導和 最後的 ans 進行求值.net

咱們先預處理出每一個區間的機率 \(g_i\) 以便於狀態轉移時使用。
再解釋一下 \(f_{i, 1/0}\) 表示的是什麼
其實表示的就是在前 \(i\) 個數中, 第 \(i\) 個數於首尾交界點是(1)否(0)相同的指望值。3d

而後咱們就考慮怎麼轉移。
咱們把這個環切成切成一條鏈, 咱們指望一個區間 [j, i] 都是同一個顏色的, 而後咱們就以 \(f_{j, 0/1}\) 進行轉移。 咱們只需將轉移的指望乘目前區間的貢獻再乘上這個區間都是同色的機率再乘於 \(m\) 種顏色中顏色的機率code

而後咱們進行分類討論。
咱們先考慮當 \(1\) 點與首尾交界點(咱們人爲添加的點, 這個點並不存在於鏈當中)不一樣色的狀況。
這個狀況咱們還能夠分兩種類, 就是 \(i\) 點和這個 \(1\) 點的顏色是否相同兩個可能
能夠得出轉移方程:blog

\[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\) 就是這個區間的貢獻get

\[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}\) 狀態轉移過來的。it

而後咱們考慮最後一種可能了, 就是 \(1\) 點與首尾交界點同色的狀況。
由於指望仍是轉移的指望乘目前區間的貢獻再乘上這個區間都是同色的機率再乘於 \(m\) 種顏色中顏色的機率, 因此就和前一個也是差很少, 其實就是io

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

不一樣就是由於他是同色, 因此就不用考慮佔色的狀況class

而後就是重頭戲, 計算答案了。
首先, 咱們能夠 \(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;
}
相關文章
相關標籤/搜索