Lightning Conductort题解

· · 题解

考虑N^2大暴力 ans[i]=max(a[j]+sqrt(|i-j|)-a[i] (1<=j<=n)

把绝对值拆开:

ans[i]=max(a[j]+sqrt(i-j))-a[i] (1<=j<=i)

ans[i]=max(a[j]+sqrt(j-i))-a[i] (i<j<=n)

上面两个式子显然比较对称,我们可以考虑先正着做一遍再倒着做一遍

打表课证明对于f[i]的最优决策点g[i]是单调递增的,分治即可

solve(l,r,L,R)表示f[l]~f[r]的最优决策点在L~R

令mid=(l+r)/2,O(n)扫一遍取到g[mid]

继续分治

solve(l,mid-1,L,g[mid])

solve (mid+1,r,g[mid],R)

代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
long double f1[6000000],f2[6000000];
long long a[6000000];
long long read()
{
    long long ret(0);
    char ch=getchar();
    while (ch<'0' || ch>'9') ch=getchar();
    while (ch>='0' && ch<='9')
    {
        ret=(ret<<1)+(ret<<3)+ch-48;
        ch=getchar();
    }
    return ret;
}
void solve1(int L,int R,int l,int r)
{
    if (L>R) return;
    int mid=(L+R)>>1,g(0);
    long double tmp(0);
    f1[mid]=a[mid];
    for (int i=l;i<=min(r,mid);i++)
    {
        tmp=a[i]+sqrt(double(mid-i));
        if (tmp>f1[mid]) f1[mid]=tmp,g=i;
    }
    if (g==0) g=mid; f1[mid]-=a[mid];
    solve1(L,mid-1,l,g); 
    solve1(mid+1,R,g,r);
}
void solve2(int L,int R,int l,int r)
{
    if (L>R) return ;
    int mid=(L+R)>>1,g(0);
    long double tmp(0);
    f2[mid]=a[mid];
    for (int i=r;i>=max(mid,l);i--)
    {
        tmp=a[i]+sqrt(double(i-mid));
        if (tmp>f2[mid]) f2[mid]=tmp,g=i;
    }
    if (g==0) g=mid; f2[mid]-=a[mid];
    solve2(L,mid-1,l,g);
    solve2(mid+1,R,g,r);
}
int main()
{
    int n=read();
    for (int i=1;i<=n;i++) a[i]=read();
    solve1(1,n,1,n);
    solve2(1,n,1,n);
    for (int i=1;i<=n;i++)
    printf("%lld \n",(long long)ceil(max(f1[i],f2[i])));
    return 0;
}