描述 Description
已知一个长度为 n 的序列 a1,a2,…,an。
对于每个 1<=i<=n,找到最小的非负整数 p 满足 对于任意的 j, aj < = ai + p - sqrt(abs(i-j))
输入格式 InputFormat
第一行 n,(1<=n<=500000)
下面每行一个整数,其中第 i 行是 ai。(0<=ai<=1000000000)
输出格式 OutputFormat
n 行,第 i 行表示对于 i,得到的 p
样例输入 SampleInput
6
5
3
2
4
2
4
样例输出 SampleOutput
2
3
5
3
5
4
$a_ja_i + p - $ 得 $ a_j + - ai p$, 于是对于每个 i 要最大化 \(a_j + \sqrt{|i-j|}\)
决策单调性优化。
#include <stdio.h>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int maxn=500005;
int i,j,t,n,m,l,r,k,z,y,x;
struct data
{
int l,r,id;
data() {}
data(int id,int l,int r): id(id),l(l),r(r) {}
}q[maxn];
int a[maxn];
double f[maxn],g[maxn];
int head,tail;
inline void read(int &x)
{
x=0;char ch=getchar();
while (ch<'0' || ch>'9') ch=getchar();
while (ch>='0' && ch<='9') x=x*10+ch-'0',ch=getchar();
}
inline double calc(int x,int y)
{
return a[y]+sqrt(abs(x-y))-a[x];
}
inline int find(int l,int r,int x,int y)
{
int mid;
while (l<r)
{
mid=(l+r)>>1;
if (calc(mid,x)<calc(mid,y)) l=mid+1;
else r=mid;
}
return l;
}
inline void dp(double *f)
{
int i,j,t;
head=1;tail=0;
for (i=1;i<=n;i++)
{
if (head<=tail && ++q[head].l>q[head].r) head++;
if (head>tail || calc(n,i)>calc(n,q[tail].id))
{
while (head<=tail && calc(q[tail].l,i)>calc(q[tail].l,q[tail].id)) tail--;
if (head>tail) q[++tail]=data(i,i,n);
else
{
t=find(q[tail].l,q[tail].r,i,q[tail].id);
q[tail].r=t-1;
q[++tail]=data(i,t,n);
}
}
f[i]=calc(i,q[head].id);
}
}
int main()
{
read(n);
for (i=1;i<=n;i++) read(a[i]);
dp(f);
reverse(a+1,a+n+1);
dp(g);
reverse(g+1,g+n+1);
for (i=1;i<=n;i++) printf("%d\n",max(0,(int)ceil(max(f[i],g[i]))));
return 0;
}