bzoj 3594: [Scoi2014]方伯伯的玉米田

时间:2022-12-16 12:29:34

3594: [Scoi2014]方伯伯的玉米田

Time Limit: 60 Sec  Memory Limit: 128 MB
Submit: 1399  Solved: 627
[Submit][Status][Discuss]

Description

方伯伯在自己的农田边散步,他突然发现田里的一排玉米非常的不美。
这排玉米一共有N株,它们的高度参差不齐。
方伯伯认为单调不下降序列很美,所以他决定先把一些玉米拔高,再把破坏美感的玉米拔除掉,使得剩下的玉米的高度构成一个单调不下降序列。
方伯伯可以选择一个区间,把这个区间的玉米全部拔高1单位高度,他可以进行最多K次这样的操作。拔玉米则可以随意选择一个集合的玉米拔掉。
问能最多剩多少株玉米,来构成一排美丽的玉米。

Input

第1行包含2个整数n,K,分别表示这排玉米的数目以及最多可进行多少次操作。
第2行包含n个整数,第i个数表示这排玉米,从左到右第i株玉米的高度ai。

Output

输出1个整数,最多剩下的玉米数。

SampleInput

3 1

2 1 3

SampleOutput

3

HINT

1 < N < 10000,1 < K ≤ 500,1 ≤ ai ≤5000

       从贪心的角度,显然有从i到n整体提高要比i到某个r提高优。因为当提高范围为r(r!=n)时,无非两种情况一种是在[r+1,n]存在一个庄稼原来比(I,r]中的某一个使得在r以前长度最大值的点大于或等于,另一种是没有更大的。那么对于第二种对于答案没有贡献,我们从i到n拔高也就没影响,而当出现第一种时,可能由于多次拔高使得原本可以在[r+1,n]之间可以有贡献的点失败了,那么显然没有从i到n拔高更优。

       不优化的姿势呢显然。

       F[i][j]表示第i个位置时(必须使用第i个位置)使用了j次技能的最大长度。所以F[i][j]=max(F[x][y])(x<i,y<j,a[x]<=a[i]+y-j)===>(x<i,y<j,a[x]+y<=a[i]+j)。显然对于每次添加,都是现在已有状态都是满足x<i。现在我们可以将y与a[x]+y搞成树状数组,每次添加都是在左下角矩形中选一个最大值。然后这两维就可以优化为log2(n)*log2(m+max(a[i]));

总时间复杂度就是O(n*k* log2(n)*log2(m+max(a[i])))。恩,反正过了=-=。

 1 #include<cstdio>
2 #include<iostream>
3 #define lowbit(x) (x&(-x))
4 using namespace std;
5 const int N=10050;
6 int n,m,mx;
7 int a[N];
8 int c[N][550];
9 void add(int x,int y,int w){
10 for(int i=x;i<=mx;i+=lowbit(i))
11 for(int j=y;j<=m+1;j+=lowbit(j))
12 c[i][j]=max(w,c[i][j]);
13 }
14 inline int sum(int x,int y){
15 int ans=0;
16 for(int i=x;i;i-=lowbit(i))
17 for(int j=y;j;j-=lowbit(j))
18 ans=max(ans,c[i][j]);
19 return ans;
20 }
21 int f[N][550];
22 int main(){
23 scanf("%d%d",&n,&m);
24 for(int i=1;i<=n;i++){scanf("%d",a+i);mx=a[i]>mx?a[i]:mx;}
25 mx+=m;
26 int ans=0;
27 for(int i=1;i<=n;i++){
28 for(int j=m;j>=0;j--){
29 f[i][j]=sum(a[i]+j,j+1)+1;
30 // printf("f[%d][%d]=%d\n",i,j,f[i][j]);
31 add(a[i]+j,j+1,f[i][j]);
32 ans=max(ans,f[i][j]);
33 }
34 }
35 printf("%d",ans);
36 }
37 /*
38 3 1
39 2 1 3
40 */