题意
给出长度为
n
的序列
思路
现在对于这一道题,定义 gi=maxnk=1(hk+∣i−k∣‾‾‾‾‾‾√)
先把绝对值拆开,分类讨论
观察到 ∣i−k∣‾‾‾‾‾‾√ 是单调递减的,所以这个东西是具有决策单调性的,也就是说对于点 i,j(i<j) 的决策点 ki,kj 一定有 ki≤kj
定义 Solve(l,r,L,R) 为当前待 DP 的区间是 [l,r] 此时的最优决策区间是 [L,R]
我们先暴力 DP 出 l,r 的中点的 DP 值,同时记录最优决策点的位置 pos ,那么对于 mid 之后的点的决策肯定不会越过 pos , pos 相当于分界点,最优决策区间分成两端。
由于 mid 的 DP 值已经求出来了,所以不需要算,继续递归到
Solve(l,mid−1,L,pos),Solve(mid+1,r,pos,R)
对于每一个最优决策在分治树上只会出现 log 次,所以时间复杂度为 O(nlogn)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
template <typename Tp>Tp Max(const Tp &a, const Tp &b) {return a > b ? a : b;}
template <typename Tp>Tp Min(const Tp &a, const Tp &b) {return a < b ? a : b;}
template <typename Tp>Tp Abs(const Tp &a) {return a > 0 ? a : -a;}
template <typename Tp>void Read(Tp &x) {
Tp in = 0, f = 1; char ch = getchar();
while(ch<'0' || ch>'9') {if(ch=='-') f = -1; ch = getchar();}
while(ch>='0' && ch<='9') {in = in*10+ch-'0'; ch = getchar();}
x = in * f;
}
typedef long long LL;
const int SN = 500000 + 10;
const int inf = 0x3f3f3f3f;
double f[SN], g[SN];
LL h[SN], pos[SN], n;
double Calc(int x, int y) {
return h[x] + sqrt(Abs(x - y)) - h[y];
}
void CDQ(int l, int r, int L, int R, double *f) {
if(l > r) return ;
int mid = (l + r) >> 1;
int limits = Min(mid, R);
int bet = limits;
f[pos[mid]] = 0;
for(int i = L; i <= limits; i++)
if(Calc(i, mid) > f[pos[mid]])
f[pos[mid]] = Calc(i, mid), bet = i;
CDQ(l, mid - 1, L, bet, f), CDQ(mid + 1, r, bet, R, f);
}
// mid 已经计算过了,只需要递归不含 mid 的两边即可
int main() {
Read(n);
for(int i = 1; i <= n; i++) Read(h[i]);
for(int i = 1; i <= n; i++) pos[i] = i;
CDQ(1, n, 1, n, f);
for(int i = 1; i <= n / 2; i++)
std::swap(h[i], h[n - i + 1]), std::swap(pos[i], pos[n - i + 1]);
CDQ(1, n, 1, n, g);
for(int i = 1; i <= n; i++)
printf("%d\n", (int) ceil(Max(g[i], f[i])));
return 0;
}