最长不下降子序列(LIS)

最长上升子序列、最长不下降子序列,解法差不多,就一点等于不等于的差别,我这里说最长不下降子序列的。

有两种解法。

一种是DP,很容易想到,就这样:

1         REP(i,n)
2         {
3             f[i]=1;
4             FOR(j,0,i-1)
5                 if(a[j]<=a[i]) f[i]=max(f[i],f[j]+1);
6         }

DP是O(n^2)的,我感觉已经不错了不过还有超碉的nlogn的方法。

nlogn的方法:

用栈和二分查找。

遇到一个元素a[i],若它不小于栈顶s[top],直接入栈;若大于栈顶,则在栈中二分查找,用它替换栈中比它大的第一个元素。最终栈的大小就是最长不下降子序列的长度(栈中元素并不一定是这个子序列,只有大小是一样的)

例题:http://acm.hdu.edu.cn/showproblem.php?pid=1950

DP代码(例题TLE):

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<map>
 8 #include<set>
 9 using namespace std;
10 #define ll __int64
11 #define usint unsigned int
12 #define mz(array) memset(array, 0, sizeof(array))
13 #define minf(array) memset(array, inf, sizeof(array))
14 #define REP(i,n) for(int i=0;i<(n);i++)
15 #define FOR(i,x,n) for(int i=(x);i<=(n);i++)
16 #define RD(x) scanf("%d",&x)
17 #define WN(x) printf("%d\n",x);
18 #define RE  freopen("D.in","r",stdin)
19 #define WE  freopen("1.out","w",stdout)
20
21 const int maxn=44444;
22
23 int a[maxn];
24 int f[maxn];
25 int main()
26 {
27     //RE;
28     int t,n,i,j;
29     int ans;
30     RD(t);
31     while(t--)
32     {
33         RD(n);
34         ans=0;
35         REP(i,n)
36             RD(a[i]);
37         REP(i,n)
38         {
39             f[i]=1;
40             FOR(j,0,i-1)
41                 if(a[j]<=a[i]) f[i]=max(f[i],f[j]+1);
42             if(f[i]>ans)ans=f[i];
43         }
44         WN(ans);
45     }
46     return 0;
47 }

nlogn代码:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<map>
 8 #include<set>
 9 #include<stack>
10 using namespace std;
11 #define ll __int64
12 #define usint unsigned int
13 #define mz(array) memset(array, 0, sizeof(array))
14 #define minf(array) memset(array, inf, sizeof(array))
15 #define REP(i,n) for(int i=0;i<(n);i++)
16 #define FOR(i,x,n) for(int i=(x);i<=(n);i++)
17 #define RD(x) scanf("%d",&x)
18 #define WN(x) printf("%d\n",x);
19 #define RE  freopen("D.in","r",stdin)
20 #define WE  freopen("1.out","w",stdout)
21
22 const int maxn=44444;
23
24 int a[maxn];
25 int s[maxn],sn;
26 int main() {
27     //RE;
28     int t,n,i,j;
29     int l,r,mid;
30     int ans;
31     RD(t);
32     while(t--) {
33         RD(n);
34         ans=0;
35         REP(i,n)
36             RD(a[i]);
37         sn=1;
38         s[0]=a[0];
39         FOR(i,1,n-1) {
40             if(s[sn-1]<=a[i]) s[sn++]=a[i];
41             else {
42                 l=0;
43                 r=sn-1;///二分找比a[i]大的第一个(s[sn-1]肯定比a[i]大,l不会加爆)
44                 while(l<=r) {
45                     mid=(l+r)>>1;
46                     if(s[mid]>a[i]) r=mid-1;
47                     else l=mid+1;
48                 }
49                 s[l]=a[i];
50             }
51         }
52         WN(sn);
53     }
54     return 0;
55 }

最长不下降子序列(LIS)

时间: 2024-10-15 05:50:17

最长不下降子序列(LIS)的相关文章

SPOJ 3943 - Nested Dolls 最长不下降子序列LIS(二分写法)

现在n(<=20000)个俄罗斯套娃,每个都有宽度wi和高度hi(均小于10000),要求w1<w2并且h1<h2的时候才可以合并,问最少能剩几个. [LIS]乍一看跟[这题]类似,但是仔细看是有区别的,其实就相当于上一题多次求LIS,每次求完LIS后把得到的序列删去,然后重新求LIS,最后输出求LIS的次数,我一开始这样写,果然就TLE了.还是要另辟蹊径. 首先用贪心思想,先按照wi从大到小排序,wi相等的情况下hi从小到大,然后求最长不下降子序列(注意可以等于).输出其长度即可. 想

1045 Favorite Color Stripe (最长不下降子序列 LIS)

Eva is trying to make her own color stripe out of a given one. She would like to keep only her favorite colors in her favorite order by cutting off those unwanted pieces and sewing the remaining parts together to form her favorite color stripe. It is

最长不下降子序列--LIS

#include <iostream> #include <vector> #include <algorithm> using namespace std; const int maxn = 100; int main() { int n; cin >> n; vector<int> datas; while (n--) { int tem; cin >> tem; datas.push_back(tem); } int dp[ma

swust oj 585--倒金字塔(LIS最长不下降子序列)

题目链接:http://acm.swust.edu.cn/problem/585/ Time limit(ms): 3000 Memory limit(kb): 65535 SWUST国的一支科学考察队到达了举世闻名的古埃及金字塔. 关于金字塔的建造一直是一个未解之谜, 有着“西方史学之父”之称的希罗多德认为,金字塔的建造是人力和牲畜,花费20 年时间从西奈半岛挖掘天然的石头运送到埃及堆砌而成.也有不少人认为是外星人修建的.人们发现胡夫金字塔的经线把地球分成东.西两个半球,它们的陆地面积是相等的

动态规划——最长不下降子序列(LIS)

最长不降子序列是这样一个问题: 下面介绍动态规划的做法. 令 dp[i] 表示以 A[i] 结尾的最长不下降序列长度.这样对 A[i] 来说就会有两种可能: 如果存在 A[i] 之前的元素 A[j] (j<i),使得 A[j]≤A[i] 且 dp[j]+1>dp[i],那么就把 A[i] 跟在以 A[j] 结尾的 LIS 后面,形成一条更长的不下降子序列(令 dp[i]=dp[j]+1). 如果 A[i] 之前的元素都比 A[i] 大,那么 A[i] 就只好自己形成一条 LIS,但是长度为 1

toj 4071 最长不下降子序列nlogn解法

题目描述:给出2D空间中的n只鸟的坐标,射手对其进行射击,要求射击的鸟的坐标越来越大,即对于第i和第i+1只鸟,要求满足:xi<=xi+1 && yi <= yi+1.求最多能射击多少只鸟. 思路:将所有点按照x坐标排序,x坐标相同则按照y坐标排序.则x方向上可以满足限制,对y方向上求最长不下降子序列即可.由于数据量较大,需要采取nlogn的优化算法. 1 #include <algorithm> 2 #include <iostream> 3 #inc

「网络流24题」最长不下降子序列问题

传送门:>Here< 题意: 给定正整数序列$x_1,...,x_n$ (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用$x_1$和$x_n$,则从给定序列中最多可取出多少个长度为$s$的不下降子序列. 思路分析 题意首先就很坑:注意第二问中的取出二字,意味着一个数字最多只能存在于一个LIS中.所以才会有第三问的假设 第一问很简单,直接暴力$O(n^2)$就好了 后面的两问需要借助于网络流.很容易想到

P2766 最长不下降子序列问题

\(\color{#0066ff}{题目描述}\) ?问题描述: 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. ?编程任务: 设计有效算法完成(1)(2)(3)提出的计算任务. \(\color{#0066ff}{输入格式}\) 第1 行有1个正整数n,表示给定序列的长度.接下来的1 行有n个正整

[网络流24题]最长不下降子序列问题

[luogu 2766] 最长不下降子序列问题 传送门 第一问: \(O(n^2)\) 的DP求LIS 为了下面叙述方便,我们将DP过程讲一遍 子状态:dp[i]表示以a[i]结尾的LIS长度 初始条件:dp[i]=1 状态转移方程:\(dp[i]=dp[j]+1(j<i,a[j]\leq a[i])\) 第二问: 我们发现若a[j]加上a[i]可以构成一个不下降子序列,则\(j<i,a[j] \leq a[i]\) 又发现每个元素只能在一个序列中,考虑拆点 建图方法: 原点S=0,T=2n+