可以发现每次都对后缀+1是不会劣的。考虑dp:设f[i][j]为前i个数一共+1了j次时包含第i个数的LIS长度。则f[i][j]=max(f[i][j-1],f[k][l]+1) (k<i,l<=j,a[i]+j>=a[k]+l)。容易发现这里是二维偏序,相当于查询(j,a[i]+j)左下部分的最大值,二维树状数组暴力维护,复杂度O(nklogklogv)。
#include<iostream> #include<cstdio> #include<cmath> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; int read() { int x=0,f=1;char c=getchar(); while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();} while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar(); return x*f; } #define N 10010 #define M 510 #define V 5010 int n,m,a[N],f[N][M]; int tree[M][V+M]; void ins(int x,int y,int k) { for (;x<=m+1;x+=x&-x) for (int i=y;i<=5500;i+=i&-i) tree[x][i]=max(tree[x][i],k); } int query(int x,int y) { int s=0; for (;x;x-=x&-x) for (int i=y;i;i-=i&-i) s=max(s,tree[x][i]); return s; } int main() { #ifndef ONLINE_JUDGE freopen("bzoj3594.in","r",stdin); freopen("bzoj3594.out","w",stdout); const char LL[]="%I64d\n"; #else const char LL[]="%lld\n"; #endif n=read(),m=read(); int t=0; for (int i=1;i<=n;i++) a[i]=read(); for (int i=1;i<=n;i++) { for (int j=0;j<=m;j++) { if (j) f[i][j]=f[i][j-1]; f[i][j]=max(f[i][j],query(j+1,a[i]+j)+1); } for (int j=0;j<=m;j++) ins(j+1,a[i]+j,f[i][j]); } for (int i=1;i<=n;i++) f[0][m]=max(f[0][m],f[i][m]); cout<<f[0][m]; return 0; }