BZOJ4850[Jsoi2016]灯塔

xiaoxiao2021-02-28  42

标签:RMQ

题目

题目传送门

Description

JSOI的国境线上有N一座连续的山峰,其中第i座的高度是hi.

为了简单起见,我们认为这N座山峰排成了连续一条直线.

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

hjhi+p+|ij| h j ≤ h i + p + | i − j |

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

1< N ≤ 10^5

0 < hi ≤ 10^9

Input

输入一行包含一个正整数N。

接下来N行,第i行包含一个正整数ℎi,表示第i座山峰的高度。

Output

第i行包含一个非负整数,表示在第i座山峰上修建灯塔所需要的最小高度Pi

Sample Input

6 5 3 2 4 2 4

Sample Output

2 3 5 3 5 4

题意

给定一个序列h,对于每个hi都存在一个常数p,满足下面的式子

hjhi+p+|ij|1jn) h j ≤ h i + p + | i − j | ( 1 ≤ j ≤ n )

求出每个hi对应的p

分析

hjhi+p+|ij|1jn) h j ≤ h i + p + | i − j | ( 1 ≤ j ≤ n )

移项得到:

hjhi|ij|p h j − h i − | i − j | ≤ p

对于此式,hi为恒定值,突破点在sqrt(abs(i-j))上

可以发现长度为n的序列,sqrt(abs(i-j))最多只有sqrt(n)种取值

那么对于每段的sqrt(abs(i-j)),找出这段中最大的hj就可以了,这可以用RMQ解决

O(nn) 时 间 复 杂 度 O ( n n )

常数较大,垫底gg

看来还是要去补补整体二分的锅啊

code

#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<algorithm> #define rep(i,a,b) for(register int i=a;i<=b;i++) #define dep(i,a,b) for(register int i=a;i>=b;i--) #define ll long long #define mem(x,num) memset(x,num,sizeof x) #define reg(x) for(int i=last[x];i;i=e[i].next) using namespace std; inline ll read(){ ll f=1,x=0;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; } const int maxn=1e5+6; int n,h[maxn],f[maxn][36],bit[maxn],blo; void RMQ(){ rep(i,1,n)f[i][0]=h[i]; rep(j,1,blo) rep(i,1,n) if(i+(1<<j)<=n)f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]); } inline int query(int l,int r){ int Len=bit[r-l+1]; return max(f[l][Len],f[r-(1<<Len)+1][Len]); } void doit(int x){ int i=1,j=x-1,ans=0; while(true){ int len=i*i-(i-1)*(i-1),k=max(j-len+1,1); if(k>j)break;int Max=query(k,j); ans=max(ans,Max-h[x]+i); if(k==1)break; j=k-1;i++; } i=1,j=x+1; while(true){ int len=i*i-(i-1)*(i-1),k=min(n,j+len-1); if(k<j)break;int Max=query(j,k); ans=max(ans,Max-h[x]+i); if(k==n)break; j=k+1;i++; } printf("%d\n",ans); } int main() { n=read(); blo=(int)(log((double)n)/log(2.0)); rep(i,1,n)bit[i]=(int)(log((double)i)/log(2.0)); rep(i,1,n)h[i]=read(); RMQ(); rep(i,1,n)doit(i); return 0; }
转载请注明原文地址: https://www.6miu.com/read-2623716.html

最新回复(0)