HDU4604.Deque——nlogn求最长上升子序列的长度

http://acm.hdu.edu.cn/showproblem.php?pid=4604

把一个序列中的元素放到队列里面,有3种操作,对于第i个元素

1.放到队头2.放到队尾3.舍弃

求最长上升序列的长度

法1:求出每个以a[i]为起点的最长不升子序列的长度,和最长不降子序列的长度,两个相加再减去a[i]重复的次数

法2:把当前序列复制两个,一个逆序,求总共的最长上升子序列的长度,然后奇偶避免重复

//法1
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#define foreach(v) (v).begin(),(v).end()
#define pk push_back
const int maxn = 100010;
using namespace std;
int num[maxn];
int down[maxn],up[maxn],down_same[maxn],up_same[maxn];
int n;
vector<int> vi;
void solve(int dp[],int same[])
{
    vi.clear();
    for(int i=n;i>=1;--i){
        int a=lower_bound(foreach(vi),num[i])-vi.begin();
        int b=upper_bound(foreach(vi),num[i])-vi.begin();
        if(b==vi.size()||vi.empty()){
            vi.pk(num[i]);
            dp[i]=vi.size();
        }else{
            vi[b]=num[i];
            dp[i]=b+1;
        }
        same[i]=b-a+1;
    }
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%d",&num[i]);
        }
        solve(down,down_same);
        for(int i=1;i<=n;++i){
            num[i]=-num[i];
        }
        solve(up,up_same);
        int ans=0;
        for(int i=1;i<=n;++i){
            ans=max(ans,up[i]+down[i]-min(up_same[i],down_same[i]));
        }
        printf("%d\n",ans);
    }
    return 0;
}
//法2
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <algorithm>
#define foreach(v) (v).begin(),(v).end()
#define pk push_back
const int maxn = 100010;
using namespace std;
int a[maxn];
int n;
vector<int> vi;
void solve(int x)
{
    int b=upper_bound(foreach(vi),x)-vi.begin();
    if(b==vi.size()||vi.empty())
        vi.pk(x);
    else
        vi[b]=x;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif // ONLINE_JUDGE
    int T;
    scanf("%d",&T);
    while(T--){
        scanf("%d",&n);
        vi.clear();
        for(int i=1;i<=n;++i){
            scanf("%d",&a[i]);
        }
        for(int i=n;i>=1;--i){
            solve(2*a[i]+1);
        }
        for(int i=1;i<=n;++i){
            solve(2*a[i]);
        }
        printf("%d\n",vi.size());
    }
    return 0;
 }
时间: 2024-11-19 18:41:19

HDU4604.Deque——nlogn求最长上升子序列的长度的相关文章

(hdu step 3.2.2)Common Subsequence(简单dp:求最长公共子序列的长度)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 976 Accepted Submission(s): 538   Probl

DP 动态规划 Problem B 1002 求最长上升子序列的长度

Problem B  ID:1002 简单题意:给出X和Z两个字符串,求最长上升子序列的长度. 解题思路形成过程:利用矩阵.X字符串中的各字符依次作为行标,Z字符串中的各字符依次作为列标. 从第一行第一列开始逐行遍历:如果当前位置对应的两个字符相同,则在这个位置记录"前一行前一列"的对应的数+1: 如果当前位置对应的两个字符不同,则在这个位置记录"此行前一列"和"此列前一行"对应的两个数的最大值. 遍历结束后,最后一行最后一列获得的数便是最长上升

nlogn 求最长上升子序列 LIS

最近在做单调队列,发现了最长上升子序列O(nlogn)的求法也有利用单调队列的思想. 最长递增子序列问题:在一列数中寻找一些数,这些数满足:任意两个数a[i]和a[j],若i<j,必有a[i]<a[j],这样最长的子序列称为最长递增子序列. 设dp[i]表示以i为结尾的最长递增子序列的长度,则状态转移方程为: dp[i] = max{dp[j]+1}, 1<=j<i,a[j]<a[i]. 这样简单的复杂度为O(n^2),其实还有更好的方法. 考虑两个数a[x]和a[y],x&

求最长公共子序列的长度

1 #include <cstdio> 2 #include <iostream> 3 4 using namespace std; 5 6 const int max_n = 1000 + 2; 7 const int max_a = 1e6 + 10; 8 9 int n; 10 int a[max_n]; 11 int dp[max_n]; 12 13 void solve() 14 { 15 for(int i=1;i<=n;++i) 16 { 17 dp[i]=1;

(hdu step 3.2.3)Super Jumping! Jumping! Jumping!(DP:求最长上升子序列的最大和)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: Super Jumping! Jumping! Jumping! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 896 Accepted Submission(s

HDU 1025 Constructing Roads In JGShining&#39;s Kingdom[动态规划/nlogn求最长非递减子序列]

Constructing Roads In JGShining's Kingdom Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 27358    Accepted Submission(s): 7782 Problem Description JGShining's kingdom consists of 2n(n is no mor

最长上升子序列(LIS)长度的O(nlogn)算法

最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时.LIS问题可以优化为nlogn的算法.定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素.注意d中元素是单调递增的,下面要用到这个性质.首先len = 1,d[1] = a[1],然后对a[i]:若a[i]>d[len],那么len++,d[len] = a[i];否则,我们要从d[1]到d[len-1]中找到一个j,满足d[j-1]<a[i]<d[j],则根据D的定义,我们需

UVA 10635--Prince and Princess+nlgn求最长公共子序列

题目链接:点击进入 刚看到这题目还以为又碰到水题了,结果写了个O(n^2)的代码交上去超时了,才发现n有250*250那么大.后面在网上找到了一个nlgn求最长上升子序列的方法,才过了.这个nlgn算法的主要思想是将最长公共子序列转成最长上升子序列,然后用最长上升子序列nlgn的算法求解.更具体的解释可以参看这篇博文:最长公共子序列(nlogn) 代码如下: #include<iostream> #include<cstring> #include<cstdio> #i

求数组中最长递增子序列的长度

个人信息:就读于燕大本科软件工程专业 目前大三; 本人博客:google搜索"cqs_2012"即可; 个人爱好:酷爱数据结构和算法,希望将来从事算法工作为人民作出自己的贡献; 编程语言:C++ ; 编程坏境:Windows 7 专业版 x64; 编程工具:vs2008; 制图工具:office 2010 powerpoint; 硬件信息:7G-3 笔记本; 真言 怒冲北京,为理想前行. 题目 解法 使用工具栈单枝遍历数组(思路源于工具栈可以双枝遍历二叉树的方法) 栈里存放的是数组的下