BZOJ2216: [Poi2011]Lightning Conductor

来源:互联网 发布:js中什么是原型链 编辑:程序博客网 时间:2024/05/22 00:38

BZOJ2216: [Poi2011]Lightning Conductor

Dp·决策单调性

题解:

pi=max{aj|ij|}ai

只想出一个O(nnlogn)的暴力QwQ
我们发现对于一个i,|ij|的上取整是分段的,这样的段有O(n)个,因此枚举一下,线段树查询这个区间最值,更新答案即可。

然后hzw大爷用一个O(nn)的做法狂虐本蒟蒻QwQ而且很好写QwQ

就是把线段树查询换成滑动窗口维护。因为段的长度是固定的,就相当于滑动窗口维护一个定长区间的最值,然后用它直接更新相应的pi.

注意两处//take care!。滑动窗口要完全滑出去,才能更新所有左边要更新的f[].

Code:

#include <iostream>#include <cstring>#include <cstdio>#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endlusing namespace std;const int N = 200005;int f[N],n,a[N];struct Queue{    int d[N]; int head,tail;    void clear(){ head=tail=0; }    void autopop(int lim){ while(head<tail && d[head]<=lim)head++; }    void push(int i){ while(head<tail && a[d[tail-1]]<=a[i])tail--; d[tail++]=i; }    int front(){ return d[head]; }  bool empty(){ return head==tail; }} q;void work(int len,int lp,int rp,int d){//  D(len); D(lp); D(rp); D(d); E;    q.clear();    for(int i=1;i<=n+len;i++){ //take care!//      D(i); E;        q.push(i); q.autopop(i-len);        int mx=a[q.front()]+d; //      D(q.front()); D(mx); E;//      D(i-lp); D(i+rp); E;        if(i-lp>0) f[i-lp]=max(f[i-lp],mx);        if(i+rp<=n)f[i+rp]=max(f[i+rp],mx);    }}int main(){    freopen("a.in","r",stdin);    freopen("a.out","w",stdout);    scanf("%d",&n);    for(int i=1;i<=n;i++)scanf("%d",a+i);    int lp,rp;    for(int i=1;i*i<=(n<<1);i++){ //take care!        lp=i*i; rp=(i-1)*(i-1)+1; work(i*i-(i-1)*(i-1),lp,rp,i);    }    for(int i=1;i<=n;i++)printf("%d\n",max(0,f[i]-a[i]));}

正解:决策单调性!

假如k

#include <algorithm>#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <cmath>#define D(x) cout<<#x<<" = "<<x<<"  "#define E cout<<endlusing namespace std;const int N = 1000005;int n;int a[N], ans[N];double f1[N], f2[N];struct Data{    int id,l,r;    Data(){}    Data(int _id,int _l,int _r){ id=_id; l=_l; r=_r; }} q[N];double cal(int j,int i){    return a[j]-a[i]+sqrt(i-j);}void dp(double f[]){    Data *head=q, *tail=q;    *tail=Data(1,2,n); tail++;    for(int i=2;i<=n;i++){        while(head<tail && head->r < i) head++;        f[i]=cal(head->id, i);        head->l = i;        while(head<tail && head->l > head->r) head++;        while(head<tail && cal((tail-1)->id,(tail-1)->l) < cal(i,(tail-1)->l)) tail--;        if(head<tail){            int l=(tail-1)->l, r=(tail-1)->r, mid;            while(l<=r){                mid=(l+r)>>1;                if(cal((tail-1)->id,mid) < cal(i,mid)) r=mid-1;                else l=mid+1;            }            ++r;            if(r<=n){                (tail-1)->r = r-1;                *tail=Data(i,r,n); tail++;            }        }        else{            *tail=Data(i,i+1,n); tail++;        }    }}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d",a+i);    dp(f1);    reverse(a+1,a+1+n);    dp(f2);//  for(int i=1;i<=n;i++) D(f1[i]); E;//  for(int i=n;i>=1;i--) D(f2[i]); E;    for(int i=1;i<=n;i++) ans[i]=ceil(max(f1[i],f2[n-i+1]));//  for(int i=1;i<=n;i++) D(ans[i]), E;    for(int i=1;i<=n;i++) printf("%d\n",max(ans[i],0));}
原创粉丝点击