題目描述
https://www.luogu.org/problemnew/show/P5155
題解
先考慮這么一個問題,我們設f[i]表示從i點出發,按照題意去走,走到n的概率。
初值f[0]=0(到0相當於死了),f[n]=1(已經到終點了)。
f[i]=(f[i-1]+f[i+1])/2
解得f[x]=x/n。
歸納可證:對於點對a,b和中間任意一個i,i的期望為(f(a)*(b-i)+f(b)*(i-a))/(b-a)
然后我們發現一個神奇的事情:我們求得i點的期望就是ab連線上i出的y值。
這個算一算就可以出來。
然后這個題期望帶上了權值,其實一個道理,我們求最優解,其實只需要對n個點求凸包計算就好了。
細節:卡精度卡到喪心病狂,不能用點斜式,直接用上面的式子算點值就可以了。
代碼
#include<iostream> #include<cstdio> #define N 100002 using namespace std; typedef long long ll; ll n,a[N],top; inline int rd(){ int x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } struct point{ ll x,y; point operator -(const point &b)const{return point{x-b.x,y-b.y};}; double operator *(const point &b)const{return x*b.y-y*b.x;} }st[N]; int main(){ n=rd(); for(int i=1;i<=n;++i)a[i]=rd(),a[i]*=100000; st[1]=point{0,0};st[2]=point{1,a[1]};top=2; for(int i=2;i<=n+1;++i){ point x=point{i,a[i]}; while(top>1&&(st[top]-st[top-1])*(x-st[top-1])>=0)top--; st[++top]=x; } int p=2; for(int i=1;i<=n;++i){ while(st[p].x<i)p++; if(st[p].x==i)printf("%lld\n",st[p].y); else printf("%lld\n",(st[p].y*(i-st[p-1].x)+st[p-1].y*(st[p].x-i))/(st[p].x-st[p-1].x)); } return 0; }