[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;
}

浙公网安备 33010602011771号