[JSOI2016]灯塔
Description
\(JSOI\)的国境线上有\(N\)一座连续的山峰,其中第\(i\)座的高度是\(h_i\).为了简单起见,我们认为这\(N\)座山峰排成了连续一条直线.
如果在第\(i\)座山峰上建立一座高度为\(p(p\;\geq\;0)\)的灯塔,\(JYY\)发现,这座灯塔能够照亮第\(j\)座山峰,当且仅当满足如下不等式:
\(h_j\;\leq\;h_i+p+\sqrt{|i-j|}\)
\(JSOI\)国王希望对于每一座山峰,\(JYY\)都能提供建造一座能够照亮全部其他山峰的灯塔所需要的最小高度.你能帮助\(JYY\)么?
HINT
\(1<N\;\leq\;10^5,0<h_i\;\leq\;10^9\).
Solution
将式子移项,\(p\;\geq\;h_j-h_i-\sqrt{|i-j|}\),
即,对于每个\(i\),求\(max\{h_j-\sqrt{|i-j|}\}-h_i\).
显然\(\sqrt{|i-j|}\)的取值有\(\sqrt{n}\)个,枚举每个\(\sqrt{|i-j|}\),对应的\(j\)有\(2\)段区间,求区间最大值即可.
时间复杂度\(O(n\sqrt{n}logn)\).
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#define K 17
#define N 100001
struct section{
int l,r;
}s[N];
int st[N][K],h[N],m[N],sq[N],log_2[N],n,ans;
double k;
inline int read(){
int ret=0;char c=getchar();
while(!(c>='0'&&c<='9'))
c=getchar();
while(c>='0'&&c<='9'){
ret=ret*10+c-'0';c=getchar();
}
return ret;
}
inline int sqr(int k){
return k*k;
}
inline int max(int x,int y){
return x>y?x:y;
}
inline void ini_st(){
log_2[1]=0;
for(int i=2;i<=n;i++){
log_2[i]=log_2[i-1];
if((1<<log_2[i]+1)==i)
log_2[i]++;
}
for(int i=n;i>=1;i--){
st[i][0]=h[i];
for(int j=1;(i+(1<<j)-1)<=n;j++)
st[i][j]=max(st[i][j-1],st[i+(1<<j-1)][j-1]);
}
}
inline int ask(int l,int r){
if(l<1) l=1;
if(r>n) r=n;
int len=r-l+1,k=log_2[len];
return max(st[l][k],st[r-(1<<k)+1][k]);
}
inline void init(){
scanf("%d",&n);
k=sqrt(n);
int l=(int)(k);
if(k>l) l++;
for(int i=1;i<=n;i++)
scanf("%d",&h[i]);
for(int i=1;i<=l;i++){
s[i].l=sqr(i-1)+1;
s[i].r=sqr(i);
for(int j=s[i].l;j<=s[i].r;j++)
sq[j]=i;
}
ini_st();
for(int i=1;i<=n;i++,ans=0){
for(int j=sq[i-1];j>=1;j--){
ans=max(ans,ask(i-s[j].r,i-s[j].l)+j);
}
for(int j=sq[n-i];j>=1;j--){
ans=max(ans,ask(i+s[j].l,i+s[j].r)+j);
}
printf("%d\n",max(0,ans-h[i]));
}
}
int main(){
freopen("light.in","r",stdin);
freopen("light.out","w",stdout);
init();
fclose(stdin);
fclose(stdout);
return 0;
}