其实看到这道题是毫无思路的。
先简化思路,对于每个i,求max{aj+sqrt(|i-j|)}-ai
把这个式子分成前后两部分,即max(max{aj+sqrt(i-j)},max{ak+sqrt(k-i)})-ai (j<=i<=k)
然后,我们发现其实这个式子是有单调性的,所以可以用那种二分优化单调性dp的方式做。
整体二分是这种单调性dp的一种写法。
void solve1(int l,int r,int L,int R)
{
if (l>r) return;
int mid=(l+r)/2;
int pos=0;
double mx=0.0;
for (int i=L;i<=R && i<=mid;i++)
if ((double)a[i]+sqrt(mid-i)>=mx) pos=i,mx=(double)a[i]+sqrt(mid-i);
f[mid]=a[pos]+ceil(sqrt(mid-pos));
solve1(l,mid-1,L,pos);
solve1(mid+1,r,pos,R);
}
l,r是当前要计算的序列,L,R是决策的两端点,每次暴力计算mid位置的值,然后把整个序列分为两部分,也算是一种整体二分的写法吧。
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 500010
using namespace std;
int a[maxn];
int f[maxn],g[maxn];
int n,m;
void solve1(int l,int r,int L,int R)
{
if (l>r) return;
int mid=(l+r)/2;
int pos=0;
double mx=0.0;
for (int i=L;i<=R && i<=mid;i++)
if ((double)a[i]+sqrt(mid-i)>=mx) pos=i,mx=(double)a[i]+sqrt(mid-i);
f[mid]=a[pos]+ceil(sqrt(mid-pos));
solve1(l,mid-1,L,pos);
solve1(mid+1,r,pos,R);
}
void solve2(int l,int r,int L,int R)
{
if (l>r) return;
int mid=(l+r)/2;
int pos=0;double mx=0.0;
for (int i=R;i>=L && i>=mid;i--)
if ((double)a[i]+sqrt(i-mid)>=mx) pos=i,mx=(double)a[i]+sqrt(i-mid);
g[mid]=a[pos]+ceil(sqrt(pos-mid));
solve2(l,mid-1,L,pos);
solve2(mid+1,r,pos,R);
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
solve1(1,n,1,n);
solve2(1,n,1,n);
for (int i=1;i<=n;i++) printf("%d\n",max(f[i],g[i])-a[i]);
return 0;
}