Description
Bessie为了存钱给她的牛棚新建一间隔间,开始在当地的马戏团里表演,通过在平衡木上小心地来回走动来展示她卓越的平衡能力。Bessie能够通过表演赚到的钱取决于她最终成功跳下平衡木的位置。平衡木上从左向右的位置记为0,1,…,N+1。如果Bessie到达了位置0或是N+1,她就会从平衡木的一端掉下去,遗憾地得不到报酬。如果Bessie处在一个给定的位置k,她可以进行下面两项中的任意一项:
- 投掷一枚硬币。如果背面朝上,她前往位置k-1,如果正面朝上,她前往位置k+1(也就是说,每种可能性1/2的概率)。
- 跳下平衡木,获得f(k)的报酬(1≤f(k)≤10^9)。
Bessie意识到她并不能保证结果能够得到某一特定数量的报酬,这是由于她的移动是由随机的掷硬币结果控制。然而,基于她的起始位置,她想要求出当她进行一系列最优的决定之后,她能够得到的期望报酬(“最优”指的是这些决定能够带来最高可能的期望报酬)。例如,如果她的策略能够使她以1/2的概率获得10的报酬,1/4的概率获得8的报酬,1/4的概率获得0的报酬,那么她的期望报酬为加权平均值10(1/2)+8(1/4)+0(1/4)=7
Solution
根据题意列出方程(一开始读入为
a
a
a,最后答案为
f
f
f):
f
i
=
max
(
a
i
,
1
2
(
f
i
−
1
+
f
i
+
1
)
)
f_i=\max(a_i,{1\over 2}(f_{i-1}+f_{i+1}))
fi=max(ai,21(fi−1+fi+1))。然而这个方程会互相影响,而且是取
max
\max
max,没法解方程。
所以想到这样的暴力:先把所有
f
f
f初始化为
a
a
a,然后暴力不断调整
f
f
f。这样要调整很多次,显然不行。观察需要调整的条件:
f
i
<
1
2
(
f
i
−
1
+
f
i
+
1
)
f_i<{1\over 2}(f_{i-1}+f_{i+1})
fi<21(fi−1+fi+1),即
f
i
−
f
i
−
1
<
f
i
+
1
−
f
i
f_i-f_{i-1}<f_{i+1}-f_i
fi−fi−1<fi+1−fi,然后发现,就是差分后前面比后面要小!设
g
i
=
f
i
−
f
i
−
1
g_i=f_i-f_{i-1}
gi=fi−fi−1,观察调整后的
g
g
g,我们又发现,
g
i
=
g
i
+
1
=
g_i=g_{i+1}=
gi=gi+1=原来的
g
i
g_i
gi和
g
i
+
1
g_{i+1}
gi+1的平均数!然后就可以搞了,每次变平均数相当于把两段合并为一段,而且最多只会合并
n
−
1
n-1
n−1次,用个堆维护就可以了。
注意最后算答案的时候要避免一切精度误差。
Code
#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
const double eps=1e-8;
int read()
{
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return x*f;
}
int n,st,ed;LL g[Maxn],a[Maxn],b[Maxn];double f[Maxn];
struct Node{double v,sum;int l,r,pre,nxt;}p[Maxn];
double V[Maxn];
struct P{double v;int id;P(double _v,int _id){v=_v,id=_id;}};
bool operator<(P a,P b)
{
if(abs(a.v-b.v)>=eps)return a.v>b.v;
return a.id>b.id;
}
bool operator==(P a,P b){return(a.id==b.id&&abs(a.v-b.v)<eps);}
priority_queue<P>q,q0;
void merge(int x,int y)
{
p[x].v=(p[x].sum+p[y].sum)/((double)p[y].r-p[x].l+1);
p[x].r=p[y].r;p[x].sum+=p[y].sum;
q0.push(P(V[y],y));
if(ed==y)ed=x,p[x].nxt=-1,V[x]=inf;
else p[x].nxt=p[y].nxt,p[p[x].nxt].pre=x,V[x]=p[x].v-p[p[x].nxt].v;
q.push(P(V[x],x));
if(p[x].pre!=-1)
{
q0.push(P(V[p[x].pre],p[x].pre));
V[p[x].pre]=p[p[x].pre].v-p[x].v;
q.push(P(V[p[x].pre],p[x].pre));
}
}
int main()
{
n=read();f[0]=f[n+1]=a[0]=a[n+1]=b[0]=b[n+1]=0;
for(int i=1;i<=n;i++)f[i]=b[i]=read();
for(int i=n+1;i;i--)f[i]-=f[i-1],p[i].sum=p[i].v=f[i],p[i].l=p[i].r=i,p[i].pre=i-1,p[i].nxt=i+1;
for(int i=1;i<=n+1;i++)a[i]=a[i-1]+f[i];
p[1].pre=p[n+1].nxt=-1;st=1,ed=n+1;
for(int i=1;i<=n;i++)
{
V[i]=p[i].v-p[i+1].v;
q.push(P(V[i],i));
}
V[n+1]=inf;q.push(P(V[n+1],n+1));
int lst=-1;
while(1)
{
while(!q0.empty()&&q.top()==q0.top())q.pop(),q0.pop();
P t=q.top();q.pop();
if(t.v>eps)break;
merge(t.id,p[t.id].nxt);
}
g[0]=g[n+1]=0;
int x=st;
while(x!=-1)
{
g[p[x].r]=100000LL*b[p[x].r];
for(int i=p[x].r-1;i>=p[x].l;i--)
{
g[i]=g[p[x].r]-(100000LL*(a[p[x].r]-a[p[x].l-1])*((LL)p[x].r-i))/((LL)p[x].r-p[x].l+1);
if(a[p[x].r]>a[p[x].l-1])g[i]-=(((100000LL*(a[p[x].r]-a[p[x].l-1])*((LL)p[x].r-i))%((LL)p[x].r-p[x].l+1))!=0);
}
x=p[x].nxt;
}
for(int i=1;i<=n;i++)printf("%lld\n",g[i]);
}