zoukankan      html  css  js  c++  java
  • 最长上升子序列加强版(树状数组优化dp)

    题目

    Description

    给出N个数,它们各不相同,求最长上升子序列 

    Input

    先给出一个数字N,代表有N组数据
    对于每组数据,先给出一个数字TOT,TOT小于等于40000.
    接下来有TOT个数字,为1到40000的某个排列.

    Output

    针对每组数据,输出最长上升序列的长度

    Sample Input

    4
    6
    4 2 6 3 1 5
    10
    2 3 4 5 6 7 8 9 10 1
    8
    8 7 6 5 4 3 2 1 9 5 8 9 2 3 1 7 4 6

    Sample Output

    3
    9
    1
    4

    思路:

    本是一道dp题,但数据给了加强,那么就需要优化;

    首先来看看dp的代码:

        dp[1]=1;
        for(ll i=1;i<=n;i++)
        {
            ll sum=0;
            for(ll j=1;j<=i;j++)
            if(a[j]<a[i])
                sum=max(sum,dp[j]);
            dp[i]=sum+1;
        }
        ll ans=0;
        for(ll i=1;i<=n;i++)
            ans=max(ans,dp[i]);
        printf("%lld
    ",ans);

    那么怎么优化呢?-----树状数组

    我们看到代码中有两行 

    for(ll j=1;j<=i;j++)
            if(a[j]<a[i])

    一般有这个代码的dp题目都可以用树状数组来优化;

    如果不信的巨佬看看我之前写的树状数组优化题目;

    所以

    for(ll j=1;j<=i;j++)
    if(a[j]<a[i])
        sum=max(sum,dp[j]);

    就可以转化为求1-a[i]的最大值

    如下网址:https://www.cnblogs.com/wzx-RS-STHN/p/13193271.html(树状数组中求1-x的最大值);

     

    代码

    #include<bits/stdc++.h>
    typedef long long ll;
    using namespace std;
    inline ll read()
    {
        ll a=0,f=1; char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
        while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
        return a*f;
    }
    ll n,mx;
    ll sum[40001],a[40001];
    inline ll lowbit(ll x)
    {
        return x&(-x);
    }
    inline void insert(ll x,ll y)//加入 
    {
        while(x<=mx)//!!! 
        {
            sum[x]=max(sum[x],y);//cout<<"a"<<x<<" "<<y<<endl;改代码的痕迹 
            x+=lowbit(x);
        }
    }
    inline ll findout(ll x)//查找 
    {
        ll ans=0;
        while(x)
        {
            ans=max(ans,sum[x]);//cout<<"x"<<x<<endl;
            x-=lowbit(x);
        }
        return ans;
    }
    int main()
    {
        ll o=read();
        while(o--)
        {
            mx=0;
            memset(sum,0,sizeof(sum));//清零 
            memset(a,0,sizeof(a));
            n=read();
            for(ll i=1;i<=n;i++)
                a[i]=read(),
                mx=max(mx,a[i]);
            insert(a[1],1);//先把第一个加入,因为第一个的dp[1]总是1 
            ll ans=0;
            for(ll i=2;i<=n;i++)
            {
    //            if(a[i]==5)
    //                cout<<sum[4]<<endl改代码的艰难痕迹 
                ll x=findout(a[i]);
                ans=max(ans,x+1);
    //            cout<<a[i]<<" "<<x<<endl;
                insert(a[i],x+1);
            }
            printf("%lld
    ",ans);//就这么多了,没什么讲的 
        }
    }
  • 相关阅读:
    shell 脚本判断linux 的发行版本
    notepad++ 正则学习记录
    360 加固分析
    Android的静默安装
    Linux下调整根目录的空间大小
    linux 隐藏权限
    i针对网段开放端口 (命令行设置)
    python 删除文件/夹
    字符串截取
    echo 不换行
  • 原文地址:https://www.cnblogs.com/wzx-RS-STHN/p/13381782.html
Copyright © 2011-2022 走看看