【一维偏序】【最长上升子序列】【最长非降子序列】

两种方法,都是nlogn

树状数组型

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=100003,M=50003;
int d[N];//原数组
int f[M];
int n,big;

int lowbit(int x)
{ return x&(-x); }
//用于求上升序列
int ask(int x)//返回最后一个 小于等于x 的数的位置
{
    int pos=0;
    while(x)
        pos=max(pos,f[x]),x-=lowbit(x);
    return pos;
}
void add(int x,int pos)
{
    while(x<=big)
        f[x]=max(f[x],pos),x+=lowbit(x);
}

int main()
{
    while(~scanf("%d",&d[++n])) big=max(big,d[n]);
    n--;
    int ans=1;
    for(int i=n;i;i--)
    {
        int ps=ask(d[i])+1;
        ans=max(ans,ps);
        add(d[i],ps);//这是非降,就是插入在自己位置
    }//查的时候兄弟也查
    printf("%d\n",ans);

    ans=1;
    memset(f,0,sizeof(f));
    for(int i=1;i<=n;i++)
    {
        int ps=ask(d[i])+1;
        ans=max(ans,ps);
        add(d[i]+1,ps);//这是上升
    }//查的时候不查兄弟
    printf("%d\n",ans);
    return 0;
} 

二分型

#include<cstdio>#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=100003,M=50003;
int n,f[N],d[N];

int main()
{
    while(~scanf("%d",&d[++n]));
    n--;

    int ans=0;
    for(int i=n;i;i--)//这是非降
    {
        int pos=upper_bound(f+1,f+ans+1,d[i])-f;
        ans=max(ans,pos);
        f[pos]=d[i];
    }
    printf("%d\n",ans);

    ans=0,f[1]=0;
    for(int i=1;i<=n;i++)//这是上升
    {
        int pos=lower_bound(f+1,f+ans+1,d[i])-f;
        ans=max(ans,pos);
        f[pos]=d[i];
    }
    printf("%d\n",ans);

    return 0;
}

原文地址:https://www.cnblogs.com/xwww666666/p/11355669.html

时间: 2024-11-10 08:10:59

【一维偏序】【最长上升子序列】【最长非降子序列】的相关文章

动态规划-最长非降子序列

有关概念: 最长上升子序列(LIS,Longest Increasing Subsequence),在一个序列中最长的单调递增的子序列 思路: 求LIS通常有O(n2)和O(nlogn)两种算法 (1)O(n2)算法 fi表示以第i个数结尾的LIS长度 对于序列中的一个数i,在i前面枚举数j,j满足比i小且fj最大,将i作为j的后继 伪代码&状态转移方程: f1=1 for i=2...n for j=1...i-1 if(aj<ai)fi=max(fi,fj+1) 最后结果在f1~fn中取

最长上升非降子序列的长度动态规划

第一种dp从后往前: dp[i]表示以a[i]为起点的最长上升非降子序列的长度 a[8]={10,2,2,4,12,23,34,2} dp[8]={4,6,5,4,3,2,1,1}; 代码实现: 1 #include<bits/stdc++.h> 2 using namespace std; 3 void logest_increase_sub(const int*a,int ssize) 4 { 5 int *dp=new int[ssize](); 6 int *p=new int[ssi

poj 1631 最多能有多少条不交叉的线 最大非降子序列 (LIS)

左边的数字是1 2 3 4 5.... 右边的数字 第一个输入的和1连 第2个输入的和2连 右边再按从小到大排序 要求连线不能交叉 问最多能有多少条不交叉的线 假如右边有5个1 那么答案会是5 所以是最大非降子序列 Sample Input4 //T6 //n426315 Sample Output 3 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <al

最大上升子序列,最大下降子序列,最大非增子序列

For example,{1,5,2,4,3,5,6,4,7}的最大上升子序列是{1,2,3,5,6,7}长度为6 现已知原序列a[],如何求其最大上升子序列,最大下降子序列,最大非增子序列,最大非减子序列的长度?下面贴出两种方法:1.dp, 2.贪心+二分 #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> using namespace std; #defin

最长非降/下降子序列问题(DP)(待续...)

注意:抽象成以下描述即为最长非降/下降子序列问题(一维状态) 问题描述:在一个无序的序列a1,a2,a3,a4…an里,找到一个最长的序列满足:(不要求连续) ai<=aj<=ak…<=am,且i<j<k…<m.(最长非降子序列) 或 ai>aj>ak…>am,且i<j<k…<m.(最长下降子序列). 问题分析:(以最长非降子序列为例) 考虑状态数组opt[maxn]; 其中opt[i]表示a[i]时可与之前元素构成非降子序列的最大长

动态规划算法之:最长公共子序列 & 最长公共子串(LCS)

1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是"ba"或"ab") b a b c 0 0 0 a 0 1

《算法导论》读书笔记之动态规划—最长公共子序列 &amp; 最长公共子串(LCS)

From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要求在原字符串中是连续的.而最长公共子序列则并不要求连续. 2.最长公共子串 其实这是一个序贯决策问题,可以用动态规划来求解.我们采用一个二维矩阵来记录中间的结果.这个二维矩阵怎么构造呢?直接举个例子吧:"bab"和"caba"(当然我们现在一眼就可以看出来最长公共子串是

最长公共子序列|最长公共子串|最长重复子串|最长不重复子串|最长回文子串|最长递增子序列|最大子数组和

参考:http://www.ahathinking.com/archives/124.html 最长公共子序列 1.动态规划解决过程 1)描述一个最长公共子序列 如果序列比较短,可以采用蛮力法枚举出X的所有子序列,然后检查是否是Y的子序列,并记录所发现的最长子序列.如果序列比较长,这种方法需要指数级时间,不切实际. LCS的最优子结构定理:设X={x1,x2,……,xm}和Y={y1,y2,……,yn}为两个序列,并设Z={z1.z2.……,zk}为X和Y的任意一个LCS,则: (1)如果xm=

HDU - 6197 array array array (最长上升子序列&amp;最长下降子序列)

题意:对于一个序列,要求去掉正好K个数字,若能使其成为不上升子序列或不下降子序列,则“A is a magic array.”,否则"A is not a magic array.\n". 分析: 1.求一遍LCS,然后在将序列逆转,求一遍LCS,分别可得最长上升子序列和最长下降子序列的长度tmp1.tmp2. 2.n - tmp1 <= k或n - tmp2 <= k即可,需要去掉的去完之后,在已经是最长上升或最长下降的序列中随便去够k个就好了. #include<