BZOJ3594 SCOI2014方伯伯的玉米田(动态规划+树状数组)

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

  虽然看到题解清一色的都是二维BIT,仔细琢磨一下还是感觉自己原来的维护方法并没有假。容易发现f[i][j]>=f[i][j-1],那么k确定时l取值越大越好,所以两个限制至少有一个取等号。那么可以改为维护很多棵BIT,复杂度变为O(nk(logk+logv))。

#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 tree1[M][V+M],tree2[V+M][M];
void ins1(int x,int k,int p){while (k<=5500) tree1[x][k]=max(tree1[x][k],p),k+=k&-k;}
void ins2(int x,int k,int p){while (k<=501) tree2[x][k]=max(tree2[x][k],p),k+=k&-k;}
int query1(int x,int k){int s=0;while (k) s=max(s,tree1[x][k]),k-=k&-k;return s;}
int query2(int x,int k){int s=0;while (k) s=max(s,tree2[x][k]),k-=k&-k;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],max(query1(j,a[i]+j),query2(a[i]+j,j+1))+1);
        }
        for (int j=0;j<=m;j++)
        ins1(j,a[i]+j,f[i][j]),ins2(a[i]+j,j+1,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;
}

 

posted @ 2018-09-26 19:31  Gloid  阅读(200)  评论(0编辑  收藏  举报