[Solution to a problem / template] luogu_P3515_LightningConductor (decision monotonic

Given a sequence of length n, a1, a2, ..., an.

For each 1 <= i <= n, find the smallest non-negative integer p satisfying for any j, aj <= ai + p - sqrt (abs (ij))

Each point $ p = max (a [j] -a [i] + \ sqrt {| ij |} $, conceivable dp, $ f [i] = max (a [j] -a [i] + \ sqrt {| ij |} $

The absolute value of the more common practice to remove the discussion can be classified, for example, we only deal with $ j <i $ the case, then do it again on it backwards

For this root, sort out what the formula does not seem able to optimize the slope of the class, consider the decision monotonic,

prove:

Need license: For two decision points $ p1, p2 $ and $ i1 <i2 $, if the transfer from $ p2 $ compared to $ i1 $ move from $ p1 $ to $ i1 $ distinctions, from $ p2 $ transferred to $ i2 $ gifted than $ p1 $

Therefore, it is known $ a [p1] -a [i1] + \ sqrt {p1-i1} <a [p2] -a [i1] + \ sqrt {p2-i1} $, confirmation $ a [p1] -a [ i2] + \ sqrt {p1-i2} <a [p2] -a [i2] + \ sqrt {p2-i2} $

Found only two equations of the root, there are $ i1, i2 $ Simple, so you can start from the root, pay attention to $ i1 <i2 $, that is $ p-i1> p-i2 $, equivalent to root the argument of the function becomes a little smaller, and the same value becomes smaller sides

Then it can be thought about what slope / derivative and the like, which is the square root function of the slope of the decline, in front of and behind the argument same variation value, a magnitude relation function value change: for $ i <j, \ sqrt {i - \ Delta} - \ sqrt {i}> \ sqrt {j- \ Delta} - \ sqrt {j} $, while a small amount of change in the phase argument of a function value amount of change, it is clearly the monotonicity

Divide and conquer approach did not write

Half stack process:

1. Exclude team head all the right point less than $ i $ the elements, then the head elements left point set $ i $

2. Update $ f with team head [i] $

3. To exclude all the tail are not good decisions than $ i $

4. If the queue is empty directly into $ i $, otherwise:

  Bipartite find the turning point $ pos $, if $ pos $ does not coincide with the left end of the tail, the tail modify elements of the right point of $ pos-1 $, or pop the tail

  If $ pos <= n $ $ I $ inserted

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
const int maxn=500009;
int n,a[maxn];
double f[maxn],g[maxn],sq[maxn];
struct node{
    int p,l,r;
}q[maxn];
double calc(int j,int i){
    return a[j]+sq[i-j];
}
int bound(int t,int i){
    int pos=q[t].r+1,l=q[t].l,r=q[t].r;
    while(l<=r){
        int mid=l+r>>1;
        if(calc(q[t].p,mid)<calc(i,mid))pos=mid,r=mid-1;
        else l=mid+1;
    }
    return pos;
}
void work(){
    int head=1,tail=0,pos;
    for(int i=1;i<=n;i++){
        while(head<=tail && q[head].r<i)head++;q[head].l=i;
        f[i]=max(f[i],calc(q[head].p,i)-a[i]);
        while(head<=tail && calc(q[tail].p,q[tail].l)<calc(i,q[tail].l))tail--;
        if(head>tail)q[++tail]=(node){i,i,n};
        else{
            int pos=bound(tail,i);
            if(pos!=q[tail].l)q[tail].r=pos-1;
            else tail--;
            if(pos<=n)q[++tail]=(node){i,pos,n};
        }
    }
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),sq[i]=sqrt(i);
    work();
    for(int i=1,j=n;i<j;i++,j--)
    swap(a[i],a[j]),swap(f[i],f[j]);
    work();
    for(int i=n;i>=1;i--)
    printf("%d\n",(int)(ceil(f[i])));
    
}

 

Guess you like

Origin www.cnblogs.com/superminivan/p/11489572.html