BZOJ4850: [Jsoi2016]灯塔

来源:互联网 发布:电脑初学者软件好 编辑:程序博客网 时间:2024/04/28 02:49

BZOJ4850

很容易发现sqrt(|ij|)很多情况下都是相等的。
那么就可以考虑分块。(题目应该是hjhi+psqrt(|ij|))
sqrt(|ij|)=x时,令Mx为所有满足sqrt(|ij|)=xj中,最大的hj值。
那么p>=Mx+sqrt(|ij|)hi
一开始直接将sqrt(|ij|)=x四舍五入了。。显然错了。应该向上取整。
然后发现长度为1时,x=1,长度为2,3,4时,x=2,长度为5,6,7,8,9时,x=3……
那么(i1)2+1i2sqrt(|ij|)是相等的。就可以分块了。
对于每一块,用RMQ求出块内最大值,对于每一块,求出最大值即可。Ansi=Max(Mx+xhi)
复杂度O(NN)。只要打的不算太丑都能水过去。。QAQdsy垫底1.15s噢不能用线段树。。加个log就跑不过去了。
至于正解。。决策单调性整体二分什么的。。反正我不会

【代码】

#include <cstdio>#include <iostream>#include <algorithm>#include <cstring>#include <cmath>#define N 100005#define mod 1000000007#define INF 0x7fffffffusing namespace std;typedef long long ll;ll read(){    ll x=0,f=1;char ch=getchar();    while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}    while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}    return x*f;}int n,sum;int h[N],DP[N][30],Bit[N];void RMQ()  {       int temp=(int)(log((double)n)/log(2.0));     for(register int i=1;i<=n;i++) Bit[i]=(int)(log((double)i)/log(2.0));     for(register int i=1;i<=n;i++)          DP[i][0]=h[i];      for(register int j=1;j<=temp;j++)          for(register int i=1;i<=n;i++)              if(i+(1<<j)<=n) DP[i][j]=max(DP[i][j-1],DP[i+(1<<(j-1))][j-1]);   }      int Query(int L,int R)  {       int k=Bit[R-L+1];      return max(DP[L][k],DP[R-(1<<k)+1][k]);  }  void Solve(int x){    int i=1,j=x-1,ans=0;    while(1)    {        int len=i*i-(i-1)*(i-1);        int jj=j-len+1;jj=max(jj,1);        if(jj>j) break;        int mx=Query(jj,j);        ans=max(ans,mx-h[x]+i);        if(jj==1) break;j=jj-1;i++;    }    i=1,j=x+1;    while(1)    {        int len=i*i-(i-1)*(i-1);        int jj=j+len-1;jj=min(jj,n);        if(jj<j) break;        int mx=Query(j,jj);        ans=max(ans,mx-h[x]+i);        if(jj==n) break;j=jj+1;i++;    }    printf("%d\n",ans);}int main(){    n=read();    for(register int i=1;i<=n;i++) h[i]=read();    RMQ();    for(register int i=1;i<=n;i++) Solve(i);    return 0;}
原创粉丝点击