• 洛谷 P3287


    洛谷题面传送门

    怎么题解区全是 2log 的做法/jk,这里提供一种 1log 并且代码更短(bushi)的做法。

    首先考虑对于一个序列 (a) 怎样计算将其变成单调不降的最小代价。对于这类涉及区间操作问题,果断往差分序列方向想,我们记 (d_i=a_i-a_{i+1}),那么我们肯定会想将所有 (d) 都变成非正的,而一次操作肯定会将某个 (d_i)(1),并选择将某个 (d_i)(1)(当然也可以不操作)。加一肯定是不优的,因此我们每次肯定会选择最右边的元素作为右端点避免加一操作。因此将序列 (d) 变成非正的代价就是 (summax(d_i,0))

    接下来就可以考虑 DP 了。我们设 (dp_{i,j}) 表示序列最后一个元素是 (a_i),当前 (summax(d_i,0)=j) 最多保留了多少株玉米。那么有转移 (dp_{i,j}=maxlimits_{l<i}dp_{l,j-max(a_l-a_j,0)}+1)。直接转移是 (n^2k) 的。不过注意到这题的值域很小,因此考虑将 (max) 然后 BIT 处理偏序关系,具体来说,如果 (a_l<a_j),那么 (dp_{l,j}+1 o dp_{i,j}),我们就建立 (k) 个树状数组,第 (j) 个下标为 (t) 的位置维护 (a_l=t)(l)(dp_{l,j}) 的最大值,那么这一类转移就在第 (j) 个树状数组中取一遍前缀 (max) 即可。如果 (a_lge a_j),那么 (dp_{l,j-a_l+a_j}+1 o dp_{l,j})。不难发现这一类 DP 转移来的 (dp_{l,t}) 一定有 (t+a_l=j+a_i),于是我们建立 (5500) 个 BIT,第 (i) 个下标为 (j) 的位置维护 (t+a_l=i,a_l=j)(dp_{l,t}) 的最大值,这样这一类 DP 转移即可写成后缀和的形式,也可 BIT 维护。

    复杂度 (nklog n)

    const int MAXN=10000;
    const int MAXK=500;
    const int MAXV=5000;
    int n,k,a[MAXN+5];
    struct fenwick{
    	int t[MAXV+5];
    	void add(int x,int v){for(int i=x;i<=MAXV;i+=(i&(-i))) chkmax(t[i],v);}
    	int query(int x){int ret=0;for(int i=x;i;i&=(i-1)) chkmax(ret,t[i]);return ret;}
    } t1[MAXK+MAXV+5],t2[MAXV+5];
    int main(){
    	scanf("%d%d",&n,&k);int res=0;
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=n;i++){
    		for(int j=0;j<=k;j++){
    			int val=max(t1[j+a[i]].query(MAXV-a[i]+1),t2[j].query(a[i]))+1;
    			t1[j+a[i]].add(MAXV-a[i]+1,val);t2[j].add(a[i],val);chkmax(res,val);
    		}
    	} printf("%d
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    hibernate 映射<二>一对一主键关联
    C# Convert Type to T
    008 OS模块
    001基础知识补充与拓展
    005Buffer(缓冲区)
    009path模块
    002nodejs简介与安装
    007http模块
    004NPM包管理器
    003nodejs的模块化
  • 原文地址:https://www.cnblogs.com/ET2006/p/luogu-P3287.html
Copyright © 2020-2023  润新知