P3515 [POI2011]Lightning Conductor

传送门

设 $f[i]$ 表示题目要求的 $p$

那么有 $f[i]=max(f[j]+\sqrt {\left | i-j \right |})$,考虑去掉绝对值

$f[i]=max(a[j]+\sqrt {i-j}),j<=i$,$f[i]=max(a[j]+\sqrt {j-i}),i<j$

后面一半和前面一半是一样的,考虑先求出前面一半,然后再和后面取 $max$

前面一半单次转移是 $O(n)$ 的,猜一下这种方程有单调性

即如果 $i$ 的最优决策点为 $k$ ,那么 $j>i$ 的最优决策点 $l$ 一定大于等于 $k$

考虑证明:

假设不单调

那么有 $f[i]=a[k]+ \sqrt {i-k}>=a[l]+ \sqrt {i-l}$

并且有 $f[j]=a[l]+ \sqrt {j-l}>=a[k]+ \sqrt {j-k}$

上面的不等式可以变成 $a[k]-a[l]>=\sqrt {i-l}-\sqrt {i-k}$

下面的不等式可以变成 $a[k]-a[l]<=\sqrt {j-l}-\sqrt {j-k}$

和起来说明 $\sqrt {i-l}-\sqrt {i-k}<=\sqrt {j-l}-\sqrt {j-k}$

考虑 $i,j,k,l$ 在数轴上的位置,如图:

并考虑上式在图像 $y=\sqrt x$ 下的样子

由图显然 $\sqrt {i-l}-\sqrt {i-k}>\sqrt {j-l}-\sqrt {j-k}$

所以矛盾,即转移单调

然后考虑维护每个位置的最优转移点,发现我们只要记录最优转移点之间的边界和转移点的编号

这个搞个单调栈维护,更新 $f$ 时在单调栈上找到相应区间,更新边界时用二分即可

具体看代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
typedef double db;
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<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e6+7;
int n,a[N];
int pos[N],Q[N];
db f[N],sqr[N];//注意double
inline db calc(int i,int j) { return 1.0*a[j]+sqr[i-j]-a[i]; }//计算dp值
inline int find(int x,int y)//二分出转移点x,y之间的边界
{
    int l=y,r=n,mid,res=l-1;
    while(l<=r)
    {
        mid=l+r>>1;
        if(calc(mid,x)>calc(mid,y)) l=mid+1,res=mid;
        else r=mid-1;
    }
    return res;
}
void work()
{
    int l=1,r=0; memset(pos,0,sizeof(pos));
    for(int i=1;i<=n;i++)
    {
        while(l<r && pos[l]<i ) l++;//找到控制i的区间
        f[i]=max(f[i],calc(i,Q[l]));
        while(l<r && calc(pos[r-1],Q[r])<calc(pos[r-1],i)) r--;//把不优的区间去掉
        pos[r]=find(Q[r],i); Q[++r]=i;
    }
}
int main()
{
    n=read(); for(int i=1;i<=n;i++) a[i]=read(),sqr[i]=sqrt(i);
    work(); reverse(a+1,a+n+1); reverse(f+1,f+n+1);/*记得f也要翻转*/ work();
    for(int i=n;i;i--) printf("%d\n",max((int)ceil(f[i]),0));
    return 0;
}

 

转载于:https://www.cnblogs.com/LLTYYC/p/11380859.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值