• [BZOJ4850][JSOI2016]灯塔(分块/决策单调性优化DP)


    第一种方法是决策单调性优化DP。

    决策单调性是指,设i>j,若在某个位置x(x>i)上,决策i比决策j优,那么在x以后的位置上i都一定比j优。

    根号函数是一个典型的具有决策单调性的函数,由于根号函数斜率递减,所以i决策的贡献的增长速度必定比j快。

    于是使用基础的决策单调性优化即可。

    注意两个问题,一是DP函数要存实数而不能存整数,因为先取整会丢失在后面的判断中需要的信息。二是记录决策作用区间的时候左端点要实时更新,即下面的p[st].l++,否则在二分时会出现错误。

     1 #include<cmath>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     5 using namespace std;
     6 
     7 const int N=100010;
     8 double f[N],g[N];
     9 int n,st,ed,h[N];
    10 struct P{ int l,r,p; }q[N];
    11 
    12 int Abs(int x){ return (x>0) ? x : -x; }
    13 double cal(int x,int y){ return h[x]-h[y]+sqrt(Abs(y-x)); }
    14 
    15 int find(P a,int b){
    16     int L=a.l,R=a.r;
    17     while (L<R){
    18         int mid=(L+R)>>1;
    19         if (cal(a.p,mid)>=cal(b,mid)) L=mid+1; else R=mid;
    20     }
    21     return L;
    22 }
    23 
    24 void work(double f[]){
    25     st=ed=1; q[1]=(P){1,n,1};
    26     rep(i,2,n){
    27         q[st].l++; if (q[st].l>q[st].r) st++;
    28         f[i]=cal(q[st].p,i);
    29         if (st>ed || (cal(q[ed].p,n)<cal(i,n))){
    30             while (st<=ed && cal(q[ed].p,q[ed].l)<cal(i,q[ed].l)) ed--;
    31             if (st>ed) q[++ed]=(P){i,n,i};
    32             else{
    33                 int t=find(q[ed],i); q[ed].r=t-1; q[++ed]=(P){t,n,i};
    34             }
    35         }
    36     }
    37 }
    38 
    39 int main(){
    40     scanf("%d",&n);
    41     rep(i,1,n) scanf("%d",&h[i]);
    42     work(f); reverse(h+1,h+n+1);
    43     work(g); reverse(g+1,g+n+1);
    44     rep(i,1,n) printf("%d
    ",max((int)ceil(max(f[i],g[i])),0));
    45     return 0;
    46 }

    第二种方法是分块。

    这题中,对于固定的i,sqrt(i-j)只有O(sqrt(n))种取值,而每种取值的区间长度也只有O(sqrt(n))个。

    预处理从每个数开始后O(sqrt(n))个数中的最大值,暴力枚举sqrt(i-j)的取值更新答案。

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<iostream>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 typedef long long ll;
     7 using namespace std;
     8 
     9 const int N=100010,K=620;
    10 int n,ans,h[N],mx[N][650];
    11 
    12 int main(){
    13     freopen("bzoj4850.in","r",stdin);
    14     freopen("bzoj4850.out","w",stdout);
    15     scanf("%d",&n);
    16     rep(i,1,n) scanf("%d",&h[i]);
    17     rep(i,1,n){
    18         mx[i][1]=h[i];
    19         rep(j,2,min(K,n-i+1)) mx[i][j]=max(mx[i][j-1],h[i+j-1]);
    20     }
    21     rep(i,1,n){
    22         ans=0;
    23         for (int pos=i,j=1,nxt; pos!=1; j++)
    24             nxt=pos-1,pos=max(pos-j*2+1,1),ans=max(ans,mx[pos][nxt-pos+1]-h[i]+j);
    25         for (int pos,j=1,nxt=i; nxt!=n; j++)
    26             pos=nxt+1,nxt=min(nxt+j*2-1,n),ans=max(ans,mx[pos][nxt-pos+1]-h[i]+j);
    27         printf("%d
    ",ans);
    28     }
    29     return 0;
    30 }
  • 相关阅读:
    听说,好久不更了......
    JavaScript中数组常用方法
    html5常用英语单词
    重写与重载的区别
    RelativeLayout以及ListView
    树莓派基础配置
    通过yum安装lnmp-phpmyadmin
    POJ1850
    基于字典序的组合生成算法
    全排序之字典排序
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10122874.html
Copyright © 2020-2023  润新知