JSOI2016 灯塔

JSOI2016 灯塔

题面描述

JSOI的国境线上有\(N\)座连续的山峰其中第\(i\)座的高度是\(h_i\).为了简单起见,我们认为这\(N\)座山峰排成了连续一条直线。

如果在第\(i\)座山峰上建立一座高度为\(p\)\((p\ge0)\)的灯塔, JYY发现,这座灯塔能够照亮第\(j\)座山峰当且仅当满足如下不等式:

\[h_j\le h_i+p-\sqrt{|i-j|} \]

JSOl国王希望对于每一座山峰, JYY 都能提供建造一座能够照亮全部其他山峰的灯塔所需要的最小高度。 你能帮助JYY么?

思路

先移项。

\[h_j+\sqrt{|i-j|}-h_i\le p \]

对于固定的\(i\),\(-h_i\)不用管,我们只需要就前面那一串的最大值就可以了。

显然,\(y=\sqrt{x}\)是一个上凸函数,它增长的速度在逐渐减缓。

也就意味着,如果一个前面的塔被后面的打败了,他就再也没有机会翻身了。

所以,这道题具有决策单调性。

二分解决即可。

代码

#include<bits/stdc++.h>
using namespace std;
const int sz=1e5+7;
int n;
int h[sz];
int pos[sz];
int ans[sz];
void solve1(int l,int r,int pl,int pr){
	if(l>r) return;
	int t=0;
	double height=0;
	int mid=(l+r)>>1;
	for(int i=min(pr,mid-1);i>=pl;i--)
	if(sqrt(mid-i)+h[i]>height){
		height=sqrt(mid-i)+h[i];
		t=i;
	}
	pos[mid]=t;
	int k=ceil(height);
	ans[mid]=max(ans[mid],k);
	solve1(l,mid-1,pl,t);
	solve1(mid+1,r,t,pr);
}
void solve2(int l,int r,int pl,int pr){
	if(l>r) return;
	int t=0;
	double height=0;
	int mid=(l+r)>>1;
	for(int i=max(mid+1,pl);i<=pr;i++)
	if(sqrt(i-mid)+h[i]>height){
		height=sqrt(i-mid)+h[i];
		t=i;
	}
	pos[mid]=t;
	int k=ceil(height);
	ans[mid]=max(ans[mid],k);
	solve2(l,mid-1,pl,t);
	solve2(mid+1,r,t,pr);
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d",&h[i]);
	solve1(1,n,1,n);
	solve2(1,n,1,n);
	for(int i=1;i<=n;i++){
		printf("%d\n",max(ans[i]-h[i],0));
	}
}
posted @ 2019-12-05 10:12  霞光  阅读(263)  评论(0编辑  收藏  举报