BZOJ4850: [Jsoi2016]灯塔

BZOJ4850

很容易发现 sqrt(|ij|) 很多情况下都是相等的。
那么就可以考虑分块。(题目应该是 hjhi+psqrt(|ij|) )
sqrt(|ij|)=x 时,令 Mx 为所有满足 sqrt(|ij|)=x j 中,最大的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+1i2 sqrt(|ij|) 是相等的。就可以分块了。
对于每一块,用 RMQ 求出块内最大值,对于每一块,求出最大值即可。 Ansi=Max(Mx+xhi)
复杂度 O(NN) 。只要打的不算太丑都能水过去。。 QAQ dsy垫底 1.15s 噢不能用线段树。。加个 log 就跑不过去了。
至于正解。。决策单调性整体二分什么的。。反正我不会

【代码】

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#define N 100005
#define mod 1000000007
#define INF 0x7fffffff
using 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值