【bzoj2216】[Poi2011]Lightning Conductor 决策单调性+整体二分

其实看到这道题是毫无思路的。

先简化思路,对于每个i,求max{aj+sqrt(|i-j|)}-ai

把这个式子分成前后两部分,即max(max{aj+sqrt(i-j)},max{ak+sqrt(k-i)})-ai  (j<=i<=k)

然后,我们发现其实这个式子是有单调性的,所以可以用那种二分优化单调性dp的方式做。

整体二分是这种单调性dp的一种写法。


void solve1(int l,int r,int L,int R)
{
    if (l>r) return;
    int mid=(l+r)/2;
    int pos=0;
    double mx=0.0;
    for (int i=L;i<=R && i<=mid;i++)
      if ((double)a[i]+sqrt(mid-i)>=mx) pos=i,mx=(double)a[i]+sqrt(mid-i);
    f[mid]=a[pos]+ceil(sqrt(mid-pos));
    solve1(l,mid-1,L,pos);
    solve1(mid+1,r,pos,R);
}

l,r是当前要计算的序列,L,R是决策的两端点,每次暴力计算mid位置的值,然后把整个序列分为两部分,也算是一种整体二分的写法吧。


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 500010 
 
using namespace std;
 
int a[maxn];
int f[maxn],g[maxn];
int n,m;
 
void solve1(int l,int r,int L,int R)
{
    if (l>r) return;
    int mid=(l+r)/2;
    int pos=0;
    double mx=0.0;
    for (int i=L;i<=R && i<=mid;i++)
      if ((double)a[i]+sqrt(mid-i)>=mx) pos=i,mx=(double)a[i]+sqrt(mid-i);
    f[mid]=a[pos]+ceil(sqrt(mid-pos));
    solve1(l,mid-1,L,pos);
    solve1(mid+1,r,pos,R);
}
 
void solve2(int l,int r,int L,int R)
{
    if (l>r) return;
    int mid=(l+r)/2;
    int pos=0;double mx=0.0;
    for (int i=R;i>=L && i>=mid;i--)
      if ((double)a[i]+sqrt(i-mid)>=mx) pos=i,mx=(double)a[i]+sqrt(i-mid);
    g[mid]=a[pos]+ceil(sqrt(pos-mid));
    solve2(l,mid-1,L,pos);
    solve2(mid+1,r,pos,R);
}
 
int main()
{
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    solve1(1,n,1,n);
    solve2(1,n,1,n);
    for (int i=1;i<=n;i++) printf("%d\n",max(f[i],g[i])-a[i]);
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值