Luogu P3287 [SCOI2014]方伯伯的玉米田
早就看到陈指导写掉的题,今天活动课调完AGC029的F有空就写了下
首先我们容易发现我们每次修改区间一定是一段后缀的形式,因为后面的元素不加白不加嘛
然后我们很容易想到一个暴力DP,设\(f_{i,j}\)表示以第\(i\)个数为结尾,第\(i\)个数被加了\(j\)次的答案长度
转移的时候枚举\(p<i,q\le j,a_p+q\le a_i+j\),\(f_{i,j}=\max \{ f_{p,q} \}+1\)
容易发现我们转移的时候有三维的限制都是小于,当枚举顺序这一维不看的时候,其实就是一个二维数点问题
具体地,我们将\(f_{i,j}\)表示为一个坐标为\((j,a_i+j)\)的点,因此对于某个\(f_{i,j}\),它的值就等于所有它左下角的最大值加\(1\)
因此我们现在就需要一个可以求二维前缀最大值的数据结构,显然直接用二维树状数组即可
然后要注意一个细节,树状数组的下标不能为\(0\),因此加入的点应该为\((j+1,a_i+j)\)
#include<cstdio>
#include<iostream>
#define RI register int
#define CI const int&
using namespace std;
const int V=5000,K=500;
int n,k,a[(V<<1)+5],ans,tp;
class Tree_Array
{
private:
int bit[K+5][V+K+5];
public:
#define lowbit(x) (x&-x)
inline void add(RI x,CI y,CI z)
{
for (;x<=K+1;x+=lowbit(x)) for (RI i=y;i<=K+V+1;i+=lowbit(i))
bit[x][i]=max(bit[x][i],z);
}
inline int get(RI x,CI y,int ret=0)
{
for (;x;x-=lowbit(x)) for (RI i=y;i;i-=lowbit(i))
ret=max(ret,bit[x][i]); return ret;
}
#undef lowbit
}BIT;
int main()
{
RI i,j; for (scanf("%d%d",&n,&k),i=1;i<=n;++i) scanf("%d",&a[i]);
for (i=1;i<=n;++i) for (j=k;~j;--j)
BIT.add(j+1,a[i]+j,tp=BIT.get(j+1,a[i]+j)+1),ans=max(ans,tp);
return printf("%d",ans),0;
}
辣鸡老年选手AFO在即