方伯伯的玉米田(树状数组优化)(三维偏序)

zzh学长留的毒瘤题......

首先这题先明白一个性质:

     当我们选择增区间的高度时,我们应该将所选的增加的左端点到n全增大,因为我们要求

最后成的单调不下降序列长度最大,所以这样增稳赚不亏。。。。

然后那么我们发现这题最后的点的最优高度是a[n]+K确定的

设数组含义f[j][k]表示当前玉米高度j,k次操作的最长序列长度

并且我们可以把此题看作三位偏序:

1. 当前玉米位置i,由1-i-1转移

2. 当前玉米高度j,由1-j转移

3.当前玉米已操作k,由1-k-1转移

用树状数组维护j,k,(很显然了.....)

(为了节省内存所以我们第一位循环是i,这样保证我们的i是有序的,就不需要写在数组里,

其实i,j,k,任选两位都行,只是为了省内存嘛.......)

注意点:

1.循环k时倒序,(显然嘛.....当前的k若是正序,他的插入会影响当前位k的枚举)

2.预处理要注意,根据你的枚举来定,当然也可以不

3.ans值不一定选中最后一个点

 1 #include<map>
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<string>
 8 #include<vector>
 9 #define int long long
10 using namespace std;
11 int c[511][5501];
12 int a[11001];
13 int maxn;
14 int lowbit(int x){return x&(-x);}
15 int n,K;
16 void add(int x,int y,int sum)//x 第几个操作 y 高度 k第k操作
17 {
18     for(int i=x;i<=K+1;i+=lowbit(i))
19     {
20         for(int j=y;j<=maxn+K;j+=lowbit(j))
21         {
22               c[i][j]=max(c[i][j],sum);
23         }
24     }
25 }
26 int query(int x,int y)
27 {
28      int ans=0;
29      for(int i=x;i>=1;i-=lowbit(i))
30      {
31           for(int j=y;j>=1;j-=lowbit(j))
32           {
33               ans=max(ans,c[i][j]);
34           }
35      }
36      return ans;
37 }
38 int ans=0;
39 signed main()
40 {
41     scanf("%lld%lld",&n,&K);
42     for(int i=1;i<=n;++i)
43     {
44          scanf("%lld",&a[i]);
45          maxn=max(a[i],maxn);    
46     }
47     for(int i=1;i<=n;++i)
48     {
49         for(int j=K;j>=0;--j)
50         {
51              int th=query(j+1,a[i]+j)+1;
52              //printf("dp[%lld][%lld]=%lld
",j,a[i]+j);
53              ans=max(th,ans);
54              add(j+1,a[i]+j,th);   
55         }
56     }
57     //int ans=query(K+1,a[n]+K);
58     printf("%lld
",ans);
59 }
View Code

 

原文地址:https://www.cnblogs.com/Wwb123/p/11272933.html