动态规划:
首先,仔细看题目明确一点,如果要拔高,无论怎么拔,拔高的区间右端点一定是$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; }