动态规划入门 COGS1398 最长上升子序列

1398. 最长上升子序列

★   输入文件:lis1.in   输出文件:lis1.out   简单对比
时间限制:1 s   内存限制:256 MB

【题目描述】

设有整数序列A[1],A[2],A[3],…,A[m],若存在下标i1<i2<i3<…<in,且A[i1]<A[i2]<A[i3]<…<A[in],则称 序列A[1],A[2],A[3],…,A[m]中有长度为n的上升子序列A[i1] , A[i2] ,A[i3] ,…,A[in]。

请编程计算指定序列的最长上升子序列长度。

【输入格式】

第一行一个正整数n(n<1001),表示序列中整数个数;

第二行是空格隔开的n个整数组成的序列。

【输出格式】

一个正整数,表示输入文件中整数序列的最长上升子序列的长度。

【样例输入】

  7

1 7 3 5 9 4 8

【样例输出】

4

【样例说明】

 序列(1,7,3,5,9,4,8)最长上升序列有:(1,3,5,9),(1,3,5,8),(1,3,4,8),他们长度为4。
方程为f(i)=max{f(j)}+1(b

j

<b

i

且i<j)

 

这个题重在优化
首先先贴LIS代码
注意要赋到f[]数组初值(某小受就没有)
 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<algorithm>
 5 using namespace std;
 6
 7 int n;
 8 int in[10010],f[10010];
 9 int ans;
10
11 int main(){
12     scanf("%d",&n);
13     for(int i=1;i<=n;i++) scanf("%d",&in[i]),f[i]=1;
14     for(int i=2;i<=n;i++){
15         for(int j=1;j<i;j++)
16             if(in[i]>in[j]) f[i]=max(f[i],f[j]+1);
17         ans=max(ans,f[i]);
18     }
19     printf("%d",ans);
20     return 0;
21 }

单调栈优化

从前向后扫描序列列,维护一个单调栈

插?入一个数时,我们在h[] 中二分出一个位置i,使得h[i]<a[k+1]<=h[i + 1],令h[i+1]=a[k + 1] 即可

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6
 7 int n;
 8 int num[10010];
 9 int top;
10 int tmp;
11
12 void add(int t){
13     if(t>num[top]) num[++top]=t;
14     else{
15         int ll=1;
16         int rr=top;
17         int mid;
18         while(ll<=rr){
19             mid=(ll+rr)>>1;
20             if(t>num[mid]) ll=mid+1;
21             else rr=mid-1;//注意-1和+1
22         }
23         num[ll]=t;
24     }
25     return;
26 }
27
28 int main(){
29     scanf("%d",&n);
30     num[0]=-1;
31     for(int i=1;i<=n;i++) scanf("%d",&tmp),add(tmp);
32     printf("%d",top);
33     return 0;
34 } 

树状数组优化

数组离散化并用树状数组维护前缀最大值

 1 //实为最长上升子序列
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7
 8 int n;
 9 int in[10010],val[10010];
10 int len;
11 int b[10010];//b[i]以数字i结尾的子序列最长可以为的值
12 //扫描到in[k]这个位置时,b[i]中只有b[a[k]]会改变
13 //b[a[k]]=max(b[i]+1|i<a[k])
14 int ans,temp;
15
16 void add(int v,int pos){
17     for(int i=pos;i<=len;i+=i&(-i)) b[i]=max(v,b[i]);
18     return;
19 }
20
21 int ask(int pos){
22     int t=0;
23     for(int i=pos;i;i-=i&(-i)) t=max(t,b[i]);
24     return t;
25 }
26
27 int main(){
28     scanf("%d",&n);
29     for(int i=1;i<=n;i++) scanf("%d",&in[i]),val[i]=in[i];
30     sort(val+1,val+n+1);
31     len=unique(val+1,val+n+1)-val;//去重 保证最长上升
32     memset(b,0,sizeof(b));
33     ans=1;
34     for(int i=1;i<=n;i++){
35         in[i]=lower_bound(val+1,val+len+1,in[i])-val+1;//离散化???高大上
36         temp=ask(in[i]-1)+1;
37         ans=max(ans,temp);
38         add(temp,in[i]);
39     }
40     printf("%d",ans);
41 }

线段树优化

可以用树状数组优化,那么显然可用线段树

然而我码了2K挂掉了,以后再补

时间: 2024-08-15 05:06:26

动态规划入门 COGS1398 最长上升子序列的相关文章

动态规划算法3——最长上升子序列

今天我们要讲的是最长上升子序列(LIS). [题目描述] 给定N个数,求这N个数的最长上升子序列的长度. [样例输入] 7 2 5 3 4 1 7 6 [样例输出] 4 什么是最长上升子序列? 就是给你一个序列,请你在其中求出一段不断严格上升的部分,它不一定要连续. 就像这样:2,3,4,7和2,3,4,6就是序列2 5 3 4 1 7 6的两种选取方案.最长的长度是4. 那么,怎么求出它的最大上升子序列长度为4呢?这里介绍两种方法,都是以动态规划为基础的. 首先,我们先介绍较慢(O($n^2$

【动态规划】【最长公共子序列】Vijos P1111 小胖的水果

题目链接: https://vijos.org/p/1111 题目大意: 多组数据,给两个字符串s1,s2,求把s1,s2拆开从前往后合并后最短是多少 apple + peach = appleach ananas  + banana = bananas pear + peach = pearch 题目思路: [动态规划] 先求最长公共子序列,f[i][j]表示s1匹配到第i位,s2匹配到第j位的最多重叠字母数. 最终答案=len(s1)+len(s2)-f[len(s1)][len(s2)]

【动态规划】【最长上升子序列】HDU 5773 The All-purpose Zero

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5773 题目大意: T组数据,n个数(n<=100000),求最长上升子序列长度(0可以替代任何自然数) 题目思路: [动态规划][二分][最长上升子序列] 按最长上升子序列做,遇到0的时候更新所有长度的最优解.(这种暴力解法都能过?而且还比标解快?) 1 // 2 //by coolxxx 3 // 4 #include<iostream> 5 #include<algorithm&

动态规划算法解最长公共子序列LCS问题

第一部分.什么是动态规划算法 ok,咱们先来了解下什么是动态规划算法. 动态规划一般也只能应用于有最优子结构的问题.最优子结构的意思是局部最优解能决定全局最优解(对有些问题这个要求并不能完全满足,故有时需要引入一定的近似).简单地说,问题能够分解成子问题来解决. 动态规划算法分以下4个步骤: 描述最优解的结构 递归定义最优解的值 按自底向上的方式计算最优解的值   //此3步构成动态规划解的基础. 由计算出的结果构造一个最优解.   //此步如果只要求计算最优解的值时,可省略. 好,接下来,咱们

HDU 1159 Common Subsequence --- DP入门之最长公共子序列

题目链接 基础的最长公共子序列 #include <bits/stdc++.h> using namespace std; const int maxn=1e3+5; char c[maxn],d[maxn]; int dp[maxn][maxn]; int main() { while(scanf("%s%s",c,d)!=EOF) { memset(dp,0,sizeof(dp)); int n=strlen(c); int m=strlen(d); for(int i

【动态规划】【最长上升子序列】【贪心】bzoj1046 [HAOI2007]上升序列

nlogn求出最长上升子序列长度. 对每次询问,贪心地回答.设输入为x.当前数a[i]可能成为答案序列中的第k个,则若 f[i]>=x-k && a[i]>ans[k-1] 即可. f[i]表示以a[i]开头的最长上升子序列长度. 但这个东西难以统计.so 我们将原序列反序,求f[i] 表示以 a[i]为结尾的最长下降子序列长度即可.最后再将f.a reverse一下. 1 #include<cstdio> 2 #include<algorithm> 3

动态规划(DP),最长递增子序列(LIS)

题目链接:http://poj.org/problem?id=2533 解题报告: 状态转移方程: dp[i]表示以a[i]为结尾的LIS长度 状态转移方程: dp[0]=1; dp[i]=max(dp[k])+1,(k<i),(a[k]<a[i]) #include <stdio.h> #define MAX 1005 int a[MAX];///存数据 int dp[MAX];///dp[i]表示以a[i]为结尾的最长递增子序列(LIS)的长度 int main() { int

动态规划——E (LIS())最长上升子序列

E - LIS Time Limit:1000MS     Memory Limit:65536KB     64bit IO Format:%I64d & %I64u Submit Status Description The world financial crisis is quite a subject. Some people are more relaxed while others are quite anxious. John is one of them. He is very

低价购买 (动态规划,变种最长下降子序列(LIS))

题目描述 “低价购买”这条建议是在奶牛股票市场取得成功的一半规则.要想被认为是伟大的投资者,你必须遵循以下的问题建议:“低价购买:再低价购买”.每次你购买一支股票,你必须用低于你上次购买它的价格购买它.买的次数越多越好!你的目标是在遵循以上建议的前提下,求你最多能购买股票的次数.你将被给出一段时间内一支股票每天的出售价(216范围内的正整数),你可以选择在哪些天购买这支股票.每次购买都必须遵循“低价购买:再低价购买”的原则.写一个程序计算最大购买次数. 这里是某支股票的价格清单: 日期  1