HDU 6284 Longest Increasing Subsequence(LIS+思维)

Longest Increasing Subsequence

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 232    Accepted Submission(s): 57


Problem Description
Bobo has a sequence  a1,a2,,an.
Let  f(x) be the length of longest *strictly* increasing subsequence after replacing all the occurrence of  0 with  x.
He would like to find  ni=1if(i).

Note that the length of longest strictly increasing subsequence of sequence  s1,s2,,sm is the largest  k
such that there exists  1i1<i2<<ikm satisfying  si1<si2<<sik.
 

Input
The input consists of several test cases and is terminated by end-of-file.

The first line of each test case contains an integer  n.
The second line contains  n integers  a1,a2,,an.
 

Output
For each test case, print an integer which denotes the result.

## Constraint

1n105
0ain
* The sum of  n does not exceed  250,000.
 

Sample Input
 
   
21 131 0 364 0 6 1 0 3
 

Sample Output
 
   
31449
 


题意:

给你一个长度为n的序列,

x从1变到n,每一次变化后,都用x替换序列里面的0,求一遍最长严格上升子序列的长度len,将答案加上len*x

最后输出答案


解析:

首先我们可以知道每一次变化,len是有一个最小值的,这个最小值就是把序列中0全部去掉所求出来的最长严格上升子序列长度lenmin。并且每一次变化最多只能让len在最小值的基础上+1,因为我们变化的只有一个数,所以在最长严格上升子序列中这个数最多只会有一次,所以每一次变化len的长度要么是[lenmin,lenmin+1]

然后上官方题解

设 fi, gi 分别表⽰以点 i 开始、结束的 LIS ⻓度,L 是原来的 LIS ⻓度。对于每个 i,找出它下⼀个 0 后⾯的 aj 满⾜ fi + gj = L,那么当 x 在[ai + 1, aj − 1] 的区间内时,答案是 L + 1.

根据官方题解,剩下的就是在得到f[],g[]下,怎么求满足条件的i,j使得fi+gj=L

当一个i,在他的下一个0后面有很多满足条件jk(k=1,2,..)使得a[i]

例如aj1aj3>aj4>....,即aj2是最大值,则起始这些区间都被包含于[ai+1,aj2-1]。所以只有找每一个i,在他的下一个0后面有很多满足条件的j中,a[j]最大的那个j就可以了。将x属于[ai + 1, aj − 1]的情况的len+1

这样我们就可以从后往前扫,根据0来分段,复杂度只要O(n)即可


这里被自己的代码坑到了,数组定义的是longlong ,带初始化的时候用int来memset,因为这个原因卡了一天....

#include

#include
#include
#include

using namespace std;
typedef long long int ll;

#define MAXN 100010



ll n,len;
ll dp[MAXN];
ll a[MAXN],g[MAXN];
ll f[MAXN],b[MAXN];
ll fz[MAXN];
vector pz;
int inc[MAXN];

ll binary_search2(ll key,ll g[],ll left,ll right)
{

    ll mid;

    while(left>1;

        if(key>g[mid]) left=mid+1;  //不加等号,严格上升

        else right=mid;

    }

    return left;

}



ll binary_search1(ll key,ll g[],ll left,ll right)
{

    ll mid;

    while(left>1;

        if(key>=g[mid]) right=mid;  //加等号,严格递减

        else left=mid+1;

    }

    return right;

}



int main()
{
    int t;
    while(scanf("%lld",&n)!=EOF)
    {
        ll j;
        int flag;
        flag=0;
        ll ans=0;
        memset(inc,0,sizeof(ll)*(n+3));    //!
        memset(fz,-1,sizeof(ll)*(n+3));    //!!
        for(int i=0;ig[len])
                j=++len;
            else
                j=binary_search2(a[i],g,1,len+1);
                //j=lower_bound(g+1,g+len+1,a[i])-g;
            g[j]=a[i];
            f[i]=j;

        }

        g[0]=MAXN;
        len=0;
        for(int i=n-1;i>=0;i--)
        {
            if(a[i]==0)
            {
                b[i]=0;
                continue;
            }
            if(a[i]=0;i--)
        {
            int en;
            if(i==pz.size()-1) en=n;
            else en=pz[i+1];
            int beg;
            if(i==0) beg=0;
            else beg=pz[i-1];

            for(j=pz[i];ja[j]+1)
                {
                   inc[a[j]+1]+=1,inc[fz[len-f[j]]]-=1;
                }
            }
        }
        for(int i=1;i<=n;i++)
        {
            inc[i]+=inc[i-1];
            if(inc[i]>0) ans+=(ll)i;
        }

        printf("%lld\n",ans);
    }
    return 0;
}

这个参考别人的代码,对求LIS进行代码量减少的一种

#include

#include
#include
#include

using namespace std;
typedef long long int ll;

#define MAXN 100010



ll n,len;
ll a[MAXN],g[MAXN];
ll f[MAXN],b[MAXN];
vector pz;
ll fz[MAXN];
int inc[MAXN];


int main()
{
    int t;
    while(scanf("%lld",&n)!=EOF)
    {
        ll j;
        int flag;
        flag=0;
        ll ans=0;
        memset(inc,0,sizeof(ll)*(n+3));
        memset(fz,-1,sizeof(ll)*(n+3));
        /*memset(g,0,sizeof(int)*(n+3));
        memset(a,-1,sizeof(int)*(n+3));
        memset(b,0,sizeof(int)*(n+3));
        memset(f,-1,sizeof(int)*(n+3));*/
        for(int i=0;ig[len])
                j=++len;
            else
                //j=binary_search2(a[i],g,1,len+1);
                j=lower_bound(g+1,g+len+1,a[i])-g;

            g[j]=a[i];
            f[i]=j;

        }

        g[0]=-MAXN;
        len=0;
        for(int i=n-1;i>=0;i--)
        {
            if(a[i]==0)
            {
                b[i]=0;
                continue;
            }
            if(-a[i]>g[len])
                j=++len;
            else
                //j=binary_search1(a[i],g,1,len+1);
                j=lower_bound(g+1,g+len+1,-a[i])-g;
            g[j]=-a[i];
            b[i]=j;
        }
        ans+=(1+n)*n/2*len;
        for(int i=pz.size()-1;i>=0;i--)
        {
            int en;
            if(i==pz.size()-1) en=n;
            else en=pz[i+1];
            int beg;
            if(i==0) beg=0;
            else beg=pz[i-1];

            for(j=pz[i];ja[j]+1)
                {
                   inc[a[j]+1]+=1,inc[fz[len-f[j]]]-=1;
                }
            }
        }
        
        for(int i=1;i<=n;i++)
        {
            inc[i]+=inc[i-1];
            if(inc[i]>0) ans+=(ll)i;
        }

        printf("%lld\n",ans);
    }
    return 0;
}

你可能感兴趣的:(动态规划,小算法,思维题)