[SCOI2014]方伯伯的玉米田

洛谷题目链接

动态规划:

首先,仔细看题目明确一点,如果要拔高,无论怎么拔,拔高的区间右端点一定是$n$,为什么呢?

这样做:

$1、$对于区间左边,不会减小以前的最优决策

$2、$对于区间内,两两之间相对高度不会发生变化

$3、$对于区间右边,会减小它们进入最优序列的可能性

所以操作区间在右端点就可以解决第三个问题

那么考虑$dp$:

设$f[i][j]$表示前面$i$个中拔高了$j$次,最多的保留数

状态转移也非常明显:$$f[i][j]=max(f[k][l])+1$$

显然需要一个可以快速求出二维最大值的数据结构

这里用的树状数组,直接套上模板,查询区间最大值即可

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#define N 10007
#define K 507
#define M 6000
#define lowbit(x) x&(-x)
using namespace std;
int n,k,maxn,ans;
int val[N],tree[M][K];
void Update(int pos,int val,int h)
{
    for(;pos<=maxn+k;pos+=lowbit(pos))
        for(int i=h;i<=k+1;i+=lowbit(i))
        	tree[pos][i]=max(tree[pos][i],val);
}
int Search(int pos,int h)
{
    int ans=0;
    for(;pos;pos-=lowbit(pos))
        for(int i=h;i;i-=lowbit(i))
        	ans=max(ans,tree[pos][i]);
    return ans;
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;++i)
    {
        scanf("%d",&val[i]);
        maxn=max(maxn,val[i]);
    }
    for(int i=1;i<=n;++i)
        for(int j=k;j>=0;--j)
        {
            int x=Search(val[i]+j,j+1)+1; 
            ans=max(ans,x);
            Update(val[i]+j,x,j+1);
        }
    printf("%d",ans);
    return 0;
}

  

posted @ 2019-01-13 19:57  模拟退火  阅读(99)  评论(0编辑  收藏  举报