以前只知道DP用 O(n2) 的做法,现在才发现求单调子序列方法好多……


◇ 模板简述

单调子序列包括 升序/降序/非升序/非降序 子序列。主要题型如下:

①在原串中找到一个最长的单调子序列;

②将原串分解为若干个单调子序列;

③通过修改元素使原串变为单调序列。

Tab: 子序列在原串中可以断开,也就是说若原串为A{a[1]~a[n]},则其子序列可以是 A'{a[b[1]]~a[b[n]]}满足 b[1]<b[2]<...<b[n]

方法的确很多,包括STL(lower_bound),DP……接着讲吧……


 

◇ 求原串中最长的单调子序列

【OpenJudge 1759】 +传送门+

 

一道非常经典的模板题——最长上升子序列。由于n最大1000,O(n2) 的算法是可以通过的。

解决这类问题的基础算法是DP。对于第i个数,我们可以找到一条以 i 结尾的上升子序列,记以 i 结尾的最长上升子序列的长度为 dp[i],也就是我们的DP状态。

如何转移?

对于第 i 个数,若存在第j个数(j<i)小于第i个数,则第i个数可以继续连接在以j结尾的最长上升子序列上,因此转移可以写成下列:

【模板时间】◆模板·III◆ 单调子序列

没有多大难度……其实只是数据规模不算大!

先附上代码(一个在 n≤3000 的情况下不会超时的版):

 1 /*Lucky_Glass*/
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 int A[1005],dp[1005],n,ans=1;
 6 int DP(int x)
 7 {
 8     if(dp[x]) return dp[x];
 9     dp[x]=1; //只有 第i个元素 本身
10     for(int i=0;i<x;i++)
11         if(A[i]<A[x])
12             dp[x]=max(dp[x],DP(i)+1);
13     return dp[x];
14 }
15 int main()
16 {
17     scanf("%d",&n);
18     for(int i=0;i<n;i++) scanf("%d",&A[i]);
19     dp[0]=1;
20     for(int i=n-1;i>=1;i--) //枚举对于以每一个元素为结尾的序列
21         ans=max(DP(i),ans);
22     printf("%d\n",ans);
23     return 0;
24 }
View Code

相关文章:

  • 2022-01-05
  • 2021-06-12
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-02-19
  • 2022-02-21
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2021-11-14
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2021-11-05
相关资源
相似解决方案