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]<a[j]且fi+gj=L,每一对得到的区间是[ai+1,ajk-1](k=1,2,..),则有[ai+1,aj1-1],[ai+1,aj2-1],[ai+1,aj3-1],....,x的值在这些区间都是会对答案产生贡献的,观察发现起始这些区间有很多是包含的关系。

例如aj1<aj2,aj2>aj3>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<cstdio>

#include<cstring>
#include<vector>
#include<algorithm>

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<int> pz;
int inc[MAXN];

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

    ll mid;

    while(left<right)

    {

        mid=(left+right)>>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<right)
    {

        mid=(left+right)>>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;i<n;i++)
        {
            scanf("%lld",&a[i]);
            if(a[i]!=0) flag=1;
        }
        if(!flag)
        {
            printf("%lld\n",(1+n)*n/2);
            continue;
        }
        pz.clear();
        //非递减
        len=0;
        g[0]=-100;
        for(int i=0;i<n;i++)
        {
            if(a[i]==0)
            {
                f[i]=0;
                pz.push_back(i);
                continue;
            }
            if(a[i]>g[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);

            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];j<en;j++)
            {
                if(a[j]==0)
                {
                    fz[0]=n+1;
                }
                else
                {
                    if(fz[b[j]]<a[j]) fz[b[j]]=a[j];
                }
            }

            for(j=beg;j<=pz[i];j++)
            {
                if(fz[len-f[j]]!=-1&&fz[len-f[j]]>a[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<cstdio>

#include<cstring>
#include<vector>
#include<algorithm>

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<int> 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;i<n;i++)
        {
            scanf("%lld",&a[i]);
            if(a[i]!=0) flag=1;
        }
        if(!flag)
        {
            printf("%lld\n",(1+n)*n/2);
            continue;
        }
        pz.clear();
        //非递减
        len=0;
        g[0]=-100;
        for(int i=0;i<n;i++)
        {
            if(a[i]==0)
            {
                f[i]=0;
                pz.push_back(i);
                continue;
            }
            if(a[i]>g[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];j<en;j++)
            {
                if(a[j]==0)
                {
                    fz[0]=n+1;
                }
                else
                {
                    if(fz[b[j]]<a[j]) fz[b[j]]=a[j];
                }
            }

            for(j=beg;j<=pz[i];j++)
            {
                if(fz[len-f[j]]!=-1&&fz[len-f[j]]>a[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;
}

猜你喜欢

转载自blog.csdn.net/qq_37025443/article/details/81043651
今日推荐