• LuoGuP1654:OSU!


    Pre

    好神奇

    Solution

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

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

    于是可以想到(题解说)

    ((X+1)^3=X^3+3cdot X^2+3cdot 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 imes 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
    ", h[n]);
    	return 0;
    }
    

    Conclusion

    比较有趣的构造方法。

  • 相关阅读:
    util包的常用类及其方法(下)
    util包的常用类及其方法(上)
    每日一记--java基础01
    每日一记--java细节之问01
    每日一记--设计模式01
    每日一记--JVM虚拟机01
    每日一记--java基础之final/static/事务
    每日一记--Mysql错误代码1067
    每日一记--AOP
    每日一记--代理模式
  • 原文地址:https://www.cnblogs.com/ChiTongZ/p/11348945.html
Copyright © 2020-2023  润新知