Luogu5155 [USACO18DEC]Balance Beam

题目链接:洛谷


这道题看起来是个期望题,但是其实是一道计算几何(这种题太妙了)

首先有一个很好的结论,在一个长度为$L$的数轴上,每次从$x$处出发,不停地走,有$\frac{x}{L}$的概率从右端点掉下去,$\frac{L-x}{L}$从左端点掉下去。

这个证明的话,感性理解一下。

令$l_x$表示从$x$处掉到左端点的概率,则$l_0=1,l_L=0$,且对于$x\in (0,L)$,$l_x=\frac{l_{x-1}+l_{x+1}}{2}$,所以$l_x$构成一个等差数列,所以得证。


显然,我们肯定是不能一直走的,不然得分肯定是0,但是我们可以“掉进”一些权值比较高的点使得答案最优,我们称这些点为“停止点”。

设从$x$处出发。

如果$x$本身就是“停止点”,那么答案就是$f_x$。($f_x$为这个点的权值)

否则$x$左右两侧的最近的“停止点”为$a,b$,这种策略的答案为$f_a*\frac{b-x}{b-a}+f_b*\frac{x-a}{b-a}$

我们发现它就是$(a,f_a),(b,f_b)$两点连接的线段在$x$处的$y$值

所以我们维护对$(x,f_x)(x\in [0,n+1])$这$n+2$个点计算出上凸包,然后就是直接贪心计算了。

 1 #include<cstdio>
 2 #define Rint register int
 3 using namespace std;
 4 typedef long long LL;
 5 const int N = 100003;
 6 struct Point {
 7     LL x, y;
 8     inline Point operator - (const Point &o) const {return (Point){x - o.x, y - o.y};}
 9     inline LL operator * (const Point &o) const {return x * o.y - y * o.x;}
10 } p[N];
11 int n, top;
12 LL a[N];
13 inline void push(Point now){
14     while(top > 1 && (now - p[top - 1]) * (p[top] - p[top - 1]) < 0) -- top;
15     p[++ top] = now;
16 }
17 int main(){
18     scanf("%d", &n);
19     for(Rint i = 0;i <= n + 1;i ++){
20         if(i && i <= n) scanf("%lld", a + i), a[i] *= 100000;
21         push((Point){i, a[i]});
22     }
23     int now = 1;
24     for(Rint i = 1;i <= n;i ++){
25         while(p[now].x < i) ++ now;
26         if(p[now].x == i) printf("%lld\n", p[now].y);
27         else {
28             printf("%lld\n", (LL) (1.0 * ((i - p[now - 1].x) * p[now].y + (p[now].x - i) * p[now - 1].y) / (p[now].x - p[now - 1].x)));
29         }
30     }
31 }
Luogu5155

 

posted @ 2019-04-16 18:40  mizu164  阅读(181)  评论(0编辑  收藏  举报