题目
Description
方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。
这排玉米一共有N
株,它们的高度参差不齐。
方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。
方伯伯可以选择一个区间,把这个区间的玉米全部拔高1单位高度,他可以进行最多K次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。
问能最多剩多少株玉米,来构成一排美丽的玉米。
Input
第1行包含2个整数n
,K
,分别表示这排玉米的数目以及最多可进行多少次操作。
第2行包含n
个整数,第i
个数表示这排玉米,从左到右第i
株玉米的高度ai
。
Output
输出1个整数,最多剩下的玉米数。
Sample Input
3 1
2 1 3
Sample Output
3
HINT
1 < N < 10000
,1 < K ≤ 500
,1 ≤ ai ≤5000
题解
我最恨的就是DP了!!!
不过为了讲课还是做了一下,毕竟tkys_Austin大佬都推荐了。
首先,通过思考我们可以得出每次操作区间的右端点一定为n
,否则后面赫鲁晓夫玉米的高度相对前面的高度就会减少,被拔的也就会变多,不满足最优
扫描二维码关注公众号,回复:
2184267 查看本文章
我们可以以DP[i][j]
表示被操作j
次后以i
为右端点的最长不下降子序列长度,显然,i
被操作了j
次,高度就为Orig[i]+j
根据这些我们就能得出状态转移方程:
dp[i][j]=max{dp[k][p]+1}, a[k]+p≤a[i]+j, p≤j, k<i
就可以得到代码了:
#include<bits/stdc++.h>
using namespace std;
int n,K;
int Orig[10010];
int DP[10010][510];
int main(int argc,char **argv) {
scanf("%d %d",&n,&K);
for(register int i(1); i<=n; ++i)scanf("%d",&Orig[i]);
for(register int i(1); i<=n; ++i) {
for(register int j(K); j>=0; --j) {
for(register int x(0); x<i; ++x) {
for(register int y(K); y>=0; --y) {
if(Orig[x]+y<=Orig[i]+j) {
DP[i][j]=max(DP[i][j],DP[x][y]+1);
}
}
}
}
}
printf("%d\n",DP[n][K]);
return 0;
}
亲身体验之后完美爆零
因为这样的时间复杂度是 \(\Theta(n^{2}k^{2})\) ,直接爆炸
怎么办呢?我们可以用二维树状数组优化
二维树状数组写法差不多,只是多了一重循环。基本思想不变,时间复杂度被优化到了\(\Theta(nklgnlgk)\) ,就AC了
代码 code
#include<bits/stdc++.h>
#define LowBit(i) ((i)&(-i))
using namespace std;
int Orig[10010],DP_BIT[10010][510];
int n,K,MaxOrigHeight,Sum,Ans;
inline void Update(int index1,int index2,int delta){
register int index(index2);
while(index1<=(MaxOrigHeight+K)){
index2=index;
while(index2<=(K+1)){
DP_BIT[index1][index2]=max(DP_BIT[index1][index2],delta);
index2+=LowBit(index2);
}
index1+=LowBit(index1);
}
}
inline int GetSum(int index1,int index2){
register int ret(0),index(index2);
while(index1){
index2=index;
while(index2){
ret=max(ret,DP_BIT[index1][index2]);
index2-=LowBit(index2);
}
index1-=LowBit(index1);
}
return ret;
}
int main(int argc,char **argv){
scanf("%d %d",&n,&K);
for(register int i(1);i<=n;++i)scanf("%d",&Orig[i]),MaxOrigHeight=max(MaxOrigHeight,Orig[i]);
for(register int i(1);i<=n;++i){
for(register int j(K);j>=0;--j){
Sum=GetSum(Orig[i]+j,j+1)+1;
Update(Orig[i]+j,j+1,Sum);
Ans=max(Ans,Sum);
}
}
printf("%d\n",Ans);
return 0;
}