传送门

 

懵懂的题解

深入理解

 

参考资料:

  [1]:LIS详解1

  [2]:LIS详解2

 

相关概念解释:

  1.串 & 子序列

    一个串的子串是指该串的一个连续的局部。

    如果不要求连续,则可称为它的子序列。

    比如对串: "abcdefg" 而言,"ab","abd","bdef" 等都是它的子序列。  

    特别地,一个串本身,以及空串也是它的子序列。

  2.最长上升子序列 & 最长不下降子序列

    最长上升子序列(Longest Increasing Subsequence,LIS),在计算机科学上是指一个序列中最长的单调递增的子序列。

    而最长不下降子序列则不一定要保证单调递增,只要保证  a[ i ] <= a[ j ] ( j > i , 且在序列范围内)即可。

现在开始回归主题:

题意:

  中文题意,不再赘述;

题解:

  第一问求最长不上升子序列的长度;

  第二问求这个序列里面最少有多少最长不上升子序列。

  难点就在与第二问,如何求呢?

  看大佬博客说“求一个序列里面最少有多少最长不上升序列等于求这个序列里最长上升序列的长度”,我也不懂为啥 /小纠结,或许,这就是大佬吧。

废话少说,上AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define INF 0x3f3f3f3f
 4 const int maxn=1e5+50;
 5 
 6 int n;
 7 int a[maxn];
 8 int dp[maxn];
 9 
10 void Solve()
11 {
12     int len=0;
13     dp[len]=INF;
14     for(int i=1;i <= n;++i)
15     {
16         if(a[i] <= dp[len])
17             dp[++len]=a[i];
18         else
19         {
20             int l=0,r=len+1;
21             while(r-l > 1)//二分出最后一个不小于 a[i] 的下标
22             {
23                 int mid=(l+r)/2;
24                 if(dp[mid] >= a[i])//注意,此处取到"=="判给了 l
25                     l=mid;
26                 else
27                     r=mid;
28             }
29             dp[r]=a[i];
30         }
31     }
32     printf("%d\n",len);
33     len=0;
34     dp[len]=-1;
35     for(int i=1;i <= n;++i)//求最长上升子序列
36     {
37         if(a[i] > dp[len])
38             dp[++len]=a[i];
39         else
40         {
41             int t=lower_bound(dp+1,dp+len+1,a[i])-dp;
42             dp[t]=a[i];
43         }
44     }
45     printf("%d\n",len);
46 }
47 
48 int main()
49 {
50     while(~scanf("%d",&a[++n]))//以回车结束输入的输入方式
51         continue;
52     n--;
53     Solve();
54 }
View Code

相关文章: