可以发现每次都对后缀+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;
}
View Code

相关文章: