zoukankan      html  css  js  c++  java
  • csu 1551(线段树+DP)

    1551: Longest Increasing Subsequence Again

    Time Limit: 2 Sec  Memory Limit: 256 MB
    Submit: 267  Solved: 112
    [Submit][Status][Web Board]

    Description

    Give you a numeric sequence. If you can demolish arbitrary amount of numbers, what is the length of the longest increasing sequence, which is made up of consecutive numbers? It sounds like Longest Increasing Subsequence at first sight. So, there is another limitation: the numbers you deleted must be consecutive.

    Input

    There are several test cases.
    For each test case, the first line of input contains the length of sequence N(1≤N≤10^4). The second line contains the elements of sequence——N positive integers not larger than 10^4.

    Output

    For each the case, output one integer per line, denoting the length of the longest increasing sequence of consecutive numbers, which is achievable by demolishing some(may be zero) consecutive numbers. 

    Sample Input

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

    Sample Output

    4
    4


    题意:给出一个序列,删除任意一段连续的数(也可以不删除),删完后最长严格递增子段(序列必须是连续的)最长。
    题解:对付这种题的能力不行啊,看了题解做的.
    分析:dp[i][0]代表未删除时以i结尾最长连续上升子序列长度,
    dp[i][1]代表删除时以i结尾最长连续上升子序列长度
    不删除时很好处理,递推过去就好了,所以可以预处理 dp[i][0]
    dp[i][1]可以从dp[i][0]转移过来
    1.dp[i][1] = dp[i-1][1]+1 (a[i]>a[i-1])
    2.dp[i][1] = dp[j][0]+1 (a[i]>a[j]&&i>j) 这里找dp[j][0]可以利用线段树维护.
    这里的更新过程和查询与此题有异曲同工之妙 http://www.cnblogs.com/liyinggang/p/5656485.html
    /**分析:dp[i][0]代表未删除时以i结尾最长连续上升子序列长度,
    dp[i][1]代表删除时以i结尾最长连续上升子序列长度
    不删除时很好处理,递推过去就好了,所以可以预处理 dp[i][0]
    dp[i][1]可以从dp[i][0]转移过来
    1.dp[i][1] = dp[i-1][1]+1 (a[i]>a[i-1])
    2.dp[i][1] = dp[j][0]+1 (a[i]>a[j]&&i>j)
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <vector>
    using namespace std;
    #define N 10005
    int dp[N][2],a[N],b[N];
    int tree[N<<2],MAX;
    void pushup(int idx)
    {
        tree[idx] = max(tree[idx<<1],tree[idx<<1|1]);
    }
    void build(int l,int r,int idx)
    {
        if(l==r)
        {
            tree[idx] = 0;
            return;
        }
        int mid = (l+r)>>1;
        build(l,mid,idx<<1);
        build(mid+1,r,idx<<1|1);
        pushup(idx);
    }
    void update(int pos,int v,int l,int r,int idx)
    {
        if(l==r)
        {
            tree[idx] = max(tree[idx],v);
            return;
        }
        int mid = (l+r)>>1;
        if(pos<=mid) update(pos,v,l,mid,idx<<1);
        else update(pos,v,mid+1,r,idx<<1|1);
        pushup(idx);
    }
    void query(int l,int r,int L,int R,int idx)
    {
        if(l>=L&&R>=r)
        {
            MAX = max(MAX,tree[idx]);
            return;
        }
        int mid = (l+r)>>1;
        if(mid>=L)  query(l,mid,L,R,idx<<1);
        if(mid<R)  query(mid+1,r,L,R,idx<<1|1);
    }
    
    int main()
    {
        int n;
        while(scanf("%d",&n)!=EOF)
        {
            for(int i=1; i<=n; i++)
            {
                scanf("%d",&a[i]);
                b[i] = a[i];
            }
            sort(b+1,b+1+n);
            int cnt = unique(b+1,b+1+n)-b;
            for(int i=1; i<=n; i++) a[i] = lower_bound(b+1,b+cnt,a[i]) - b;
            for(int i=1; i<=n; i++)
            {
                dp[i][0] = 1;
                if (i > 1 && a[i]>a[i - 1])
                    dp[i][0] = dp[i - 1][0] + 1;
            }
            build(1,n,1);
            int ans = -1;
            for(int i=1; i<=n; i++)
            {
                dp[i][1] = 1;
                if(i>1&&a[i]>1)
                {
                    if(a[i]>a[i-1]) dp[i][1] = dp[i-1][1]+1;
                    MAX = -1;
                    query(1,n,1,a[i]-1,1); /**找到最大的 dp[j][0] 满足 a[j]<a[i] && j<i,有必要解释一下这里
                        为什么是更新1~a[i]-1呢?因为我们找的是按照大小排名来的数,而不是,比如说 1 3 5 6 4
                        假设我找的是 a[5] ,所以我应该忽略中间的 5 6 ,直接找 1 3 .而我们的枚举顺序也保证了 j<i 这个条件.
                        个人觉得很巧妙.
                    */
                    dp[i][1] = max(dp[i][1],MAX+1);
                }
                update(a[i],dp[i][0],1,n,1);/**
                    更新过程同样巧妙,也是更新的按照大小排名来的顺序,不要与下标弄混了
                */
                ans = max(ans,max(dp[i][1],dp[i][0]));
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    Python3和高性能全文检索引擎Redisearch进行交互
    Django项目连接多个数据库配置
    Redisearch实现的全文检索功能服务
    python一键搭建ftp服务
    yum提示错误: error: rpmdb: BDB0113 Thread/process 9866/140290246137664 failed:
    Django + FastDFS (分布式远程服务器存储文件)
    Docker来搭建分布式文件系统FastDfs
    VSCode---REST Client接口测试辅助工具
    在Centos下使用Siege对Django服务进行压力测试
    Mysql联合索引的最左前缀原则以及b+tree
  • 原文地址:https://www.cnblogs.com/liyinggang/p/5794717.html
Copyright © 2011-2022 走看看