zoukankan      html  css  js  c++  java
  • 【BZOJ3594】[SCOI2014] 方伯伯的玉米田(二维树状数组优化DP)

    点此看题面

    大致题意: 给定一个序列,你可以从中任选(k)个区间将区间中的数都加(1),求能得到的最大的最长上升子序列长度。

    暴力(DP)

    首先一个显然的结论,每次操作区间右端点一定是(n)。这应该很好理解吧,毕竟一个数加了(1)总不会变劣。

    那么就很容易想出一个暴力(DP)(f_{i,j})表示以第(i)个数结尾、第(i)个数加了(j)时的最大的最长上升子序列长度。

    转移就是枚举(k,x),满足(k<i,xle j)(a_k+xle a_i+j),令(f_{i,j}=max{f_{k,x}}+1)

    但直接暴力枚举肯定(T)飞,需要想办法优化。

    二维树状数组优化(DP)

    其实这是一道还挺有意思的题目。

    我们把(f_{i,j})对应到二维平面上一个点((j+1,a_i+j))(之所以要用(j+1)是为了避免出现(0))。

    那么它的值其实就是它左下方所有元素最大值加(1)

    二维数点问题,自然想到二维树状数组。

    什么?树状数组还能求最大值?

    实际上我也是今天才知道,如果仅仅询问前缀最大值,树状数组是可以支持的,而且实现方法和区间求和的树状数组几乎无异。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 10000
    #define K 500
    #define V 5000
    #define Gmax(x,y) (x<(y)&&(x=(y)))
    using namespace std;
    int n,k,a[N+5];
    struct TwoD_TreeArray//二维树状数组
    {
    	int a[K+5][V+K+5];
    	I void U(RI x,CI y,CI v) {for(RI i;x<=k+1;x+=x&-x) for(i=y;i<=V+k+1;i+=i&-i) Gmax(a[x][i],v);}//单点修改
    	I int Q(RI x,CI y,RI t=0) {for(RI i;x;x-=x&-x) for(i=y;i;i-=i&-i) Gmax(t,a[x][i]);return t;}//左下区间查询
    }T;
    int main()
    {
    	RI i,j,ans=0;for(scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",a+i);
    	RI t;for(i=1;i<=n;++i) for(j=k;~j;--j) T.U(j+1,a[i]+j,t=T.Q(j+1,a[i]+j)+1),Gmax(ans,t);//DP转移
    	return printf("%d
    ",ans),0;//输出答案
    }
    
  • 相关阅读:
    Android 使用系统签名打包apk
    创业公司如何巧用工具提高团队生产力——豌豆荚创始人王俊煜讲述团队背后的“利器”
    Spring整合BoneCP+Hibernate配置数据连接池
    EhCache集群方案JGroups
    IOS 目录结构
    关于hibernate的缓存使用
    用webbrowser控件做一个资源管理器,如何得到IE控件中选中(鼠标多选)的文件名称列表?
    轮回!
    转载:谨以此文献给才毕业25年的朋友
    新的开始
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3594.html
Copyright © 2011-2022 走看看