【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;
}


你可能感兴趣的:(【bzoj2216】[Poi2011]Lightning Conductor 决策单调性+整体二分)