USACO 2018 December Contest Platinum T1: Balance Beam

题目大意

Bessie为了存钱给她的牛棚新建一间隔间,开始在当地的马戏团里表演,通过在平衡木上小心地来回走动来展示她卓越的平衡能力。

Bessie能够通过表演赚到的钱取决于她最终成功跳下平衡木的位置。平衡木上从左向右的位置记为 0,1,,N+1 。(2N1e5) 如果Bessie到达了位置 0 或是 N+1 ,她就会从平衡木的一端掉下去,遗憾地得不到报酬。

如果Bessie处在一个给定的位置 k ,她可以进行下面两项中的任意一项:

  1. 投掷一枚硬币。如果背面朝上,她前往位置 k1 ,如果正面朝上,她前往位置 k+1 (也就是说,每种可能性 1/2 的概率)。

  2. 跳下平衡木,获得 f(k) 的报酬(0f(k)1e9 )。

Bessie意识到她并不能保证结果能够得到某一特定数量的报酬,这是由于她的移动是由随机的掷硬币结果控制。然而,基于她的起始位置,她想要求出当她进行一系列最优的决定之后,她能够得到的期望报酬(“最优”指的是这些决定能够带来最高可能的期望报酬)。

例如,如果她的策略能够使她以 1/2 的概率获得 10 的报酬,1/4 的概率获得 8 的报酬,1/4 的概率获得 0 的报酬,那么她的期望报酬为加权平均值 10 * (1/2)+8 * (1/4)+0 * (1/4)=7 。

题目分析

对于给定的一个点我们要考虑的就是 跳下所得收益 和 移动后的收益期望,其中 跳下所得收益 已知,考虑如何求出 移动后的收益期望。

观察

显然,如果我们已知 某些节点x(令x∈A) 移动的期望收益比 它们的 停止收益低,即如果在 另一些点 进行移动操作,一旦移动到A中的点,最优的策略就是不再移动,称A中点为停止点。

 

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

更具体地,设这两个停止点为 a, b, (a < i < b) 那么该 点i 的移动收益 Ei va * (b-i) / (b-a) + vb*(i-a) / (b-a)    (va, vb分别为a, b点跳下所得收益)

怎么得来的呢?

考虑设在 i 开始,到 停止的概率为 Fi,由题可得 F= (Fi-1 + Fi+1)/ 2,不难发现这个式子是等差数列的描述,又因为 F0=0, FL=1 可得 Fi​ = i/L

同样地,可以得到在 i 开始,到 停止的概率为 Gi = (L - i)/ L

推广,对于上面的三个点 a, i, b  (a < i < b), Ei va * (b-i) / (b-a) + vb*(i-a) / (b-a)

至此,我们仅需考虑如何找出所有停止点

 

不难发现,若将点A (a, va),B(b, vb)在平面直角坐标系中画出,Ei 的取值即为 直线x=i 与 线段AB交点。(可用梯形面积证明)

若 vi > Ei, 则显然 点i 为一个停止点。

根据以上过程,明显可以看出 所有停止点构成了一个凸包(一个完整凸包的上半部分,也就像一个上半圆弧)

至此,只要找出所有点 (i, vi)构成的凸包,然后递推从前向后扫一遍,即可得出答案。

 1 #include<bits/stdc++.h>
 2 typedef long long ll;
 3 const int MAXN=1e5+10;
 4 
 5 int n,top;
 6 ll bse=1e5;
 7 struct Node{
 8     int x;
 9     ll y;
10     friend Node operator -(const Node &a,const Node &b){return (Node){a.x-b.x,a.y-b.y};}
11     friend ll operator *(const Node &a,const Node &b){return a.x*b.y-a.y*b.x;}
12 }a,sta[MAXN];
13 
14 inline void Push_back(Node a){
15     while(top&&(a-sta[top])*(sta[top]-sta[top-1])<=0) --top;
16     sta[++top]=a;
17 }
18 int main(){
19     scanf("%d",&n);
20     for(int i=1;i<=n;++i){
21         a.x=i;
22         scanf("%lld",&a.y);
23         a.y*=bse;
24         Push_back(a);
25     }
26     Push_back((Node){n+1,0});
27     for(int i=1,j=0;i<=n;++i){
28         while(j<top&&sta[j].x<i) ++j;
29         if(sta[j].x==i)
30             printf("%lld\n",sta[j].y);
31         else
32             printf("%lld\n",((sta[j].x-i)*sta[j-1].y+(i-sta[j-1].x)*sta[j].y)/(sta[j].x-sta[j-1].x));
33     }
34     return 0;
35 } 

 

 

 

posted @ 2019-07-20 09:35  LI_dox  阅读(396)  评论(0编辑  收藏  举报