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;
}
posted @ 2020-09-09 17:33  空気力学の詩  阅读(109)  评论(0编辑  收藏  举报