woc..sb错误害死人啊
if (t>w||calc(i,n)>calc(q[w].p,n));
多打了个分号然后调了一个小时。。
这道题还是挺神的,我好像没做过除斜率优化外的决策单调性的题。
我们令fi表示点i对应的答案,那么有
那么由于y=x√这个函数是上凸的,所以我们会发现一些性质:
令j<k,且对于一个i来说(这里假设
那么如果有aj+i−j−−−−√>ak+i−k−−−−√,但是由于i−j−−−−√的增长速度是比i−k−−−−√慢的,然后随着i的增加可能会渐渐地变成aj+i−j−−−−√<ak+i−k−−−−√,也就是说,在这段区间内j比
那么我们会发现,这个决策是存在单调性的,并且每个决策点都是一段连续区间的最优决策,那么我们维护一个单调队列,队列中维护一个三元组(l,r,p),表示点p在区间
然后反着同理再做一遍,前后的答案取max。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<map>
#include<set>
#include<vector>
#include<cstdlib>
#define N 500005
using namespace std;
int n;
int a[N];
double f[N],g[N];
struct node
{
int l,r,p;
};
node q[N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
inline double calc(int j,int i)
{
return a[j]+sqrt(abs(i-j))-a[i];
}
inline int find(node t,int x)
{
int l=t.l,r=t.r;
while (l<=r)
{
int mid=l+r>>1;
if (calc(t.p,mid)>calc(x,mid)) l=mid+1;
else r=mid-1;
}
return l;
}
void dp(double *F)
{
int t=1,w=0;
for (int i=1;i<=n;i++)
{
q[t].l++;
if (t<=w&&q[t].r<q[t].l) t++;
if (t>w||calc(i,n)>calc(q[w].p,n))
{
while (t<=w&&calc(q[w].p,q[w].l)<calc(i,q[w].l)) w--;
if (t>w)
q[++w]=(node){i,n,i};
else
{
int t=find(q[w],i);
q[w].r=t-1;
q[++w]=(node){t,n,i};
}
}
F[i]=calc(q[t].p,i);
}
}
int main()
{
n=read();
for (int i=1;i<=n;i++)
a[i]=read();
dp(f);
for (int i=1;i<=n>>1;i++)
swap(a[i],a[n-i+1]);
dp(g);
for (int i=1;i<=n;i++)
printf("%d\n",max(0,(int)ceil(max(f[i],g[n-i+1]))));
return 0;
}