您的位置:首页 > Web前端 > JavaScript

[bzoj4850][Jsoi2016]灯塔

2017-05-25 15:45 204 查看
来自FallDream的博客,未经允许,请勿转载,谢谢。

JSOI的国境线上有N一座连续的山峰,其中第ii座的高度是hi??.为了简单起见,我们认为这N座山峰排成了连续一条
直线.如果在第ii座山峰上建立一座高度为p(p≥0)的灯塔,JYY发现,这座灯塔能够照亮第jj座山峰,当且仅当满足如
下不等式:hj≤hi+p-(是减号)sqrt(|i-j|)JSOI国王希望对于每一座山峰,JYY都能提供建造一座能够照亮全部其他山峰的灯
塔所需要的最小高度.你能帮助JYY么?
1< N ≤ 10^5
0 < hi ≤ 10^9

话说这个出题人非常的不走心 同bzoj2216 5年前的题 样例都不改就扔了一个假的公式出来。
暴力比较显然,可以预处理rmq,然后根号枚举。
考虑两个点j,k,那么显然一个点分别从两个点转移的情况都是一段区间,可以二分求出最小的满足从j转移比从k转移优的i。
然后开一个单调队列,维护队列中两两相邻元素,前一个比后一个优的最小的i 单调递增。
复杂度nlogn

#include<iostream>
#include<cstdio>
#include<cmath>
#define getchar() (*S++)
#define MN 500000
#define INF 2000000000
char B[1<<26],*S=B;
using namespace std;
inline int read()
{
int x = 0 , f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1;  ch = getchar();}
while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();}
return x * f;
}

int n,a[MN+5],top,tail,q[MN+5];
double F[MN+5],G[MN+5],sq[MN+5];
inline int My_abs(int x){return x<0?-x:x;}
double Get(int x,int y){return a[x]+sq[My_abs(y-x)];}

int Calc(int x,int y)
{
int l=y,r=n,mid,ans=INF;
while(l<=r)
{
mid=l+r>>1;
if(Get(y,mid)>=Get(x,mid)) ans=mid,r=mid-1;
else l=mid+1;
}
return ans;
}

void Solve(double*f)
{
top=0;tail=1;
for(register int i=1;i<=n;++i)
{
if(top<tail||a[i]>a[q[top]])
{
while(top>tail&&Calc(q[top],i)<=Calc(q[top-1],q[top])) --top;
q[++top]=i;
}
while(top>tail&&Calc(q[tail],q[tail+1])<=i) ++tail;
f[i]=Get(q[tail],i)-a[i];
}
}

int main()
{
fread(B,1,1<<26,stdin);
n=read();
for(int i=0;i<=n;++i) sq[i]=sqrt(i);
for(int i=1;i<=n;++i) a[i]=read();
Solve(F);
for(int i=1;i<=n>>1;++i) swap(a[i],a[n+1-i]);
Solve(G);
for(int i=1;i<=n;++i) printf("%d\n",max(0,(int)ceil(max(F[i],G[n+1-i]))));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: