• 题解-USACO18DEC Balance Beam详细证明


    (翻了翻其他的题解,觉得它们没讲清楚这个策略的正确性)

    Problem

    洛谷5155

    题意概要:给定一个长为(n)的序列,可以选择以(frac 12)的概率进行左右移动,也可以结束并得到当前位置上的收益,求从每个位置开始时使用最优策略的最大期望收益是多少

    (nleq 10^5)

    Solution

    关键在于需要考虑当前是选择移动还是直接结束。一个很明了的观点:如果当前移动后的收益期望比当前位置的收益大,那么会选择移动;否则选择直接停止。直接停止的贡献已经知道,那么要求的就是当前点选择移动操作后的收益期望


    有一个结论:在长度为(L)的数轴上的位置(x)处,每次进行左右移动(左右概率都为(frac 12)),若到达(0)(L)即停止,则到达(0)停止的概率为(frac {L-x}L),到达(L)停止的概率为(frac xL)

    关于这个结论的证明,考虑设在 (i) 开始,到(L)停止的概率为(f_i),由题可得(f_i=frac {f_{i-1}+f_{i+1}}2),不难发现这个方程是等差数列的描述,又由(f_0=0,f_L=1)可得(f_i=frac xL),即可得到上面的结论

    这个结论的用处后面再说


    假设我们已知一些节点移动的期望收益比当前点停止的收益低,即如果进行随机游走,一旦到达这些点,一个极端聪明的人是绝不会继续移动的,设这些点为停止点

    会发现,如果从 (i) 出发进行移动,那么移动的期望收益一定是由 (i) 往前数第一个停止点和往后数第一个停止点贡献的

    不妨设为 (a)(b),由我们之前的结论可以得到到达 (a) 停止的概率为(frac {b-i}{b-a}),到达 (b) 停止的概率为(frac {i-a}{b-a}),由期望公式可得从 (i) 出发进行随机移动的期望收益为 (E=v_acdot frac {b-i}{b-a}+v_bcdot frac {i-a}{b-a}),比划一下会发现这是满足物理里的杠杆模型的

    现在我们得到了一个优秀的做法,就是对于每个点,找到其前后的第一个停止点,得到其移动的期望收益然后与自己的停止收益取最大值


    但如何求出所有的停止点呢?

    进一步,画个图可知,设 (a) 坐标为 ((a,v_a))(b) 坐标为 ((b,v_b)),则从 (i) 出发进行移动的期望收益是 (a,b) 所连线段与直线(x=i)的交点纵坐标,所有的停止点会满足在(x=i)时,(v_i)要比这条线段要高

    不难发现若将所有停止点 ((i,v_i))画出来一定成为一个凸包,反证法证明:若存在一个停止点在凸包内,则这个点的移动期望比停止期望大,也就是说这并不是一个停止点,与假设相悖,得证

    所以为了得到所有的停止点,只要对所有的((i,v_i))求个凸包即可

    证明真有趣

    Code

    #include <bits/stdc++.h>
    typedef long long ll;
    
    inline void read(ll&x){
    	char c11=getchar();x=0;while(!isdigit(c11))c11=getchar();
    	while(isdigit(c11))x=x*10+c11-'0',c11=getchar();
    }
    
    const int N=101000,bs=1e5;
    int n,tp;
    
    struct vec{
    	int x;ll y;
    	inline vec(){}
    	inline vec(const int&X,const ll&Y):x(X),y(Y){}
    	friend inline vec operator - (const vec&A,const vec&B) {return vec(A.x-B.x,A.y-B.y);}
    	friend inline ll operator * (const vec&A,const vec&B) {return A.x*B.y-A.y*B.x;}
    }p,st[N];
    
    void push(vec p){
    	while(tp&&(p-st[tp])*(st[tp]-st[tp-1])<=0)--tp;
    	st[++tp]=p;
    }
    
    int main(){
    	scanf("%d",&n);vec p;
    	for(int i=1;i<=n;++i)p.x=i,read(p.y),p.y*=bs,push(p);
    	push(vec(n+1,0));
    	for(int i=1,j=0;i<=n;++i){
    		while(j<tp&&st[j].x<i)++j;
    		if(st[j].x==i)printf("%lld
    ",st[j].y);
    		else printf("%lld
    ",((st[j].x-i)*st[j-1].y+(i-st[j-1].x)*st[j].y)/(st[j].x-st[j-1].x));
    	}return 0;
    }
    
  • 相关阅读:
    我们毕业了!!!@全体成员
    华东交通大学编译原理期末试卷
    软件设计师中级下午答题解题策略分析~
    Java实现旅行商最短距离
    基于SSH的医院在线挂号
    基于Java的模拟写字板的设计与实现
    基于java的雷电游戏
    基于Java的飞机大战游戏的设计与实现
    基于Java的超级玛丽游戏的设计与实现
    基于Javaee的影视创作论坛的设计与实现
  • 原文地址:https://www.cnblogs.com/penth/p/10246357.html
Copyright © 2020-2023  润新知