# P3251 [JLOI2012]时间流逝
P3251 [JLOI2012]时间流逝
Solution
设当前能量圈的集合为 \(S\),且当前期望值为 \(f(S)\)。用期望的定义直接表示:
\[f(S) = 1 + pf(P) + \frac{1 - p}{|\operatorname{suc}S|}\sum\limits_{V\in \operatorname{suc}S}f(V)
\]
注意 \(S\) 的前驱状态 \(P\) 是唯一的。分析 \(S\) 及其前驱后继,发现这个转移结构很像一棵树,且当前式子表现出来是 \(f(S)\) 同时受父节点 \(P\) 与众子节点的影响。
我们希望它能只受父节点的影响,这样就可以实现从上至下一对一转移。
假设 \(f(S) = k_Sf(P) + b_{S}\)。其中 \(k_S,b_S\) 是对每个 \(S\) 唯一的常数。
记 \(t = \frac{1 - p}{|\operatorname{suc}S|}\)。
\[f(S) = 1 + pf(P) + t\sum\limits_{V \in \operatorname{suc}S}(k_Vf(S) + b_V)
\]
记 \(\sigma_{k}(S) = \sum\limits_{V \in \operatorname{suc}S}k_V, \sigma_{b}(S) = \sum\limits_{V \in \operatorname{suc}S}b_V\)。则
\[\begin{aligned}
f(S) &= 1 + pf(P) + t\sigma_{k}(S)f(S) + t\sigma_{b}(S) \\
(1 - \sigma_{k}(S))f(S) &= pf(P) + 1 + t\sigma_{b}(S) \\
f(S) &= \frac{p}{1 - t\sigma_{k}(S)}f(P) + \frac{1 + t\sigma_{b}(S)}{1 - t\sigma_{k}(S)}
\end{aligned}
\]
dfs 的时候从大往小取,返回 pair 类型,答案即为根的时候的 \(b_S\)。
#include<bits/stdc++.h>
#define DB double
#define PDD pair<DB, DB>
#define MP make_pair
using namespace std;
const int N = 55;
int n, T, a[N];
double p;
PDD dfs(int sum, int x)
{
if(sum > T) return MP(0, 0);
DB k = 0, b = 0, t = (1 - p) / x;
for(int i = 1; i <= x; ++i)
{
PDD nxt = dfs(sum + a[i], i);
k += nxt.first;
b += nxt.second;
}
if(!sum) t = 1.0 / x;
return MP(p / (1 - t * k), (1 + t * b) / (1 - t * k));
}
int main()
{
while(~scanf("%lf %d %d", &p, &T, &n))
{
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
printf("%.3lf\n", dfs(0, n).second);
}
return 0;
}

浙公网安备 33010602011771号