点击这里查看原题
DP方程:f[i]=max{a[j]-a[i]+sqrt(abs(i-j))}(向上取整)
这个具有单调性,因此可以去掉绝对值符号,正反各做一次。
/*
User:Small
Language:C++
Problem No.:2216
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=5e5+5;
int a[M],head,tail,n;
double f[2][M];
struct no{
int l,r,p;
}q[M];
double cal(int j,int i){
return a[j]-a[i]+sqrt(abs(i-j));
}
int find(int i,no tmp){
int l=tmp.l,r=tmp.r,mid;
while(l<=r){
mid=l+r>>1;
if(cal(i,mid)<cal(tmp.p,mid)) l=mid+1;
else r=mid-1;
}
return l;
}
void dp(double *F){
head=1,tail=0;
for(int i=1;i<=n;i++){
q[head].l++;
if(head<=tail&&q[head].l>q[head].r) head++;
if(head>tail||cal(i,n)>cal(q[tail].p,n)){
while(head<=tail&&cal(i,q[tail].l)>cal(q[tail].p,q[tail].l)) tail--;
if(head<=tail){
int t=find(i,q[tail]);
q[tail].r=t-1;
q[++tail]=(no){t,n,i};
}
else q[++tail]=(no){i,n,i};
}
F[i]=cal(q[head].p,i);
}
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dp(f[0]);
for(int i=1;i<=n/2;i++) swap(a[i],a[n+1-i]);
dp(f[1]);
for(int i=1;i<=n;i++)
printf("%d\n",max(0,(int)ceil(max(f[0][i],f[1][n+1-i]))));
return 0;
}