版权声明:本文为博主原创文章,未经博主允许必须转载。 https://blog.csdn.net/C20181220_xiang_m_y/article/details/88880346
题目分析:
如果我们用f[i][j]表示前i个数用了j次操作得到的以i为右端点的最长不下降序列长度,枚举前面的决策点转移。
你会发现没办法转移,因为你不知道决策点和i的大小关系。
于是神奇的事情发生了。
你会发现,一次操作的区间一定是形如
的!
如果你拔高了区间
,那么显然拔高
不会更劣。
那么对于p<=i,对p的k次操作,对i同样有效。
那么就可以转移了!
,其中
二维树状数组优化一下,就是
的复杂度。
Code:
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstring>
#include<algorithm>
#define maxn 10005
using namespace std;
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;bool f=0;while(!isdigit(c=getc())) if(c=='-') f=1;
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0'); if(f) a=-a;
}
int n,m,mx,ans,tmp,a[maxn];
int arr[5505][505];
void upd(int x,int y,int d){
for(int i=x;i<=mx+m;i+=i&-i) for(int j=y;j<=m;j+=j&-j) arr[i][j]=max(arr[i][j],d);
}
int qmax(int x,int y){
int s=0;
for(int i=x;i;i-=i&-i) for(int j=y;j;j-=j&-j) s=max(s,arr[i][j]);
return s;
}
int main()
{
read(n),read(m),m++;//因为树状数组不能存0,所以整体向后移一位
for(int i=1;i<=n;i++) read(a[i]),mx=max(mx,a[i]);
for(int i=1;i<=n;i++)
for(int j=m;j>=1;j--){
ans=max(ans,tmp=qmax(a[i]+j,j)+1);
upd(a[i]+j,j,tmp);
}
printf("%d\n",ans);
}