[题解]P3515 [POI 2011] Lightning Conductor
题目简述
给定 \(n\) 个建筑物排成一行,编号从 \(1\) 到 \(n\)。第 \(i\) 个建筑物的高度为 \(h_i\)。若在建筑物 \(i\) 的屋顶放置一个高度为 \(p\) 的避雷针,则它能保护建筑物 \(j\) 当且仅当满足不等式:
\[h_j \leq h_i + p - \sqrt{|i - j|}
\]
其中 \(|i - j|\) 表示 \(i\) 和 \(j\) 之差的绝对值。
对于每个建筑物 \(i\),求一个非负整数 \(p_i\),表示放置在建筑物 \(i\) 上且能保护所有建筑物的避雷针的最小高度。
思路
对于单个方向:变形:\(k = \max \{ h_j + \sqrt{|i - j|} \} - h_i \quad (j < i)\),
那么问题转换为对于每个 \(i\),找前边的 \(h_j + \sqrt{|i - j|}\) 的最大值,然后这个式子显然满足决策单调性,就直接分治解决 \([1, n]\) 中 \(mid\) 的最优决策点 \(p\),对于 \([1, mid-1]\) 的中点继续找范围为 \([1, p]\) 的最优决策点,对于 \([mid + 1, r]\) 的中点继续找范围为 \([p, n]\) 的最优决策点,以此类推。最后减去 \(h_i\) 并且在正向和逆向中取最大值就是答案了。
代码
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
const int N=1e6+10;
int n,h[N],f[N];
double w(int i,int j){return 1.0*h[i]+sqrt(1.0*(abs(i-j)));}
void solve(int l,int r,int optl,int optr)
{
if(l>r)return;
int mid=(l+r)>>1,p=optl;
for(int i=optl;i<=min(optr,mid);i++)
if(w(i,mid)>w(p,mid))p=i;
f[mid]=max(f[mid],(int)ceil(w(p,mid)));
solve(l,mid-1,optl,p);
solve(mid+1,r,p,optr);
}
signed main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>h[i];
solve(1,n,1,n);
reverse(h+1,h+1+n);
reverse(f+1,f+1+n);
solve(1,n,1,n);
reverse(h+1,h+1+n);
reverse(f+1,f+1+n);
for(int i=1;i<=n;i++)
cout<<f[i]-h[i]<<endl;
return 0;
}

浙公网安备 33010602011771号