LuoGuP1654:OSU!

本文探讨了一种基于动态规划的优化方法,用于计算特定序列中以某元素为右端点的期望长度。通过巧妙地利用数学公式,将复杂度降低,实现了高效的状态转移。文章详细解释了如何通过预处理和递推公式来解决这一问题,同时提供了完整的代码实现。

Pre

好神奇

Solution

首先不要像我一样设\(f[i]\)表示\(i\)处为1的答案,并尝试枚举左端点,会想到\(DP\)的优化上面。

实际上考虑\(f[i]\)的来源,首先是\(a[i]\)\(1\)的时候,难以直接转移,因为贡献是\(X^3\)

于是可以想到(题解说)

\((X+1)^3=X^3+3\cdot X^2+3\cdot X+1\)

这样的话可以求\(a[i]=1\)时,以\(a[i]\)为右端点的\(X^2\)的期望长度和\(X\)的期望长度。

求法就玄学了。

上代码

f[i] = p[i] * (f[i - 1] + 1);//X
g[i] = p[i] * (g[i - 1] + 2 * f[i - 1] + 1);//X^2

\(f\)的转移的正确性不说了。

\(g\)的转移的正确性可以说一说。

考虑期望可以表示为所有的路径的长度的平均值(就是相同路径的出现次数之比为概率之比)。

这样的话期望\(=\frac{sum(len^2)}{cnt}\)

平方过后期望\(=\frac{sum((len+1)^2)}{cnt}\)

也就是\(=\frac{sum(len^2)+2\times sum(len)+sum(1)}{cnt}\)

这样直接展开后就可以从\(f\)转移了。

然后是状态转移

h[i] = p[i] * (h[i - 1] + 3 * g[i - 1] + 3 * f[i - 1] + 1) + (1 - p[i]) * h[i - 1];

揣摩一下就可以了。

Code

#include <cstdio>
#define ll long long
#define xx first
#define yy second
using namespace std;
const int N = 100000 + 5;
int n;
double p[N + 5], f[N + 5], g[N + 5], h[N + 5];
int main () {
    #ifdef chitongz
    freopen ("x.in", "r", stdin);
    #endif
    scanf ("%d", &n);
    for (int i = 1; i <= n; ++i) scanf ("%lf", &p[i]);
    for (int i = 1; i <= n; ++i) {
        f[i] = p[i] * (f[i - 1] + 1);
        g[i] = p[i] * (g[i - 1] + 2 * f[i - 1] + 1);
        h[i] = p[i] * (h[i - 1] + 3 * g[i - 1] + 3 * f[i - 1] + 1) + (1 - p[i]) * h[i - 1];
    }
    printf ("%.1lf\n", h[n]);
    return 0;
}

Conclusion

比较有趣的构造方法。

转载于:https://www.cnblogs.com/ChiTongZ/p/11348945.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值