【动态规划基础】求最长不下降序列

最长不下降子序列问题

题目描述

给定正整数序列 x 1 … , x n x_1 \ldots, x_n x1,xn

  1. 计算其最长不下降子序列的长度 s s s
  2. 如果每个元素只允许使用一次,计算从给定的序列中最多可取出多少个长度为 s s s 的不下降子序列。
  3. 如果允许在取出的序列中多次使用 x 1 x_1 x1 x n x_n xn(其他元素仍然只允许使用一次),则从给定序列中最多可取出多少个不同的长度为 s s s 的不下降子序列。

a 1 , a 2 , … , a s a_1, a_2, \ldots, a_s a1,a2,,as 为构造 S S S 时所使用的下标, b 1 , b 2 , … , b s b_1, b_2, \ldots, b_s b1,b2,,bs 为构造 T T T 时所使用的下标。且 ∀ i ∈ [ 1 , s − 1 ] \forall i \in [1,s-1] i[1,s1],都有 a i < a i + 1 a_i \lt a_{i+1} ai<ai+1 b i < b i + 1 b_i \lt b_{i+1} bi<bi+1。则 S S S T T T 不同,当且仅当 ∃ i ∈ [ 1 , s ] \exists i \in [1,s] i[1,s],使得 a i ≠ b i a_i \neq b_i ai=bi

输入格式

第一行有一个正整数 n n n,表示给定序列的长度。接下来的一行有 n n n 个正整数 x 1 , . . . , x n x_1, ..., x_n x1,...,xn

输出格式

  • 第 1 行是最长不下降子序列的长度 s s s
  • 第 2 行是可取出的长度为 s s s 的不下降子序列个数。
  • 第 3 行是允许在取出的序列中多次使用 x 1 x_1 x1 x n x_n xn 时可取出的长度为 s s s不同的不下降子序列个数。

样例

样例输入

4
3 6 2 5

样例输出

2
2
3

提示

1 ≤ n ≤ 500 1 \le n\le 500 1n500

基本思想

最长不下降子序列问题是一个经典的算法问题,可以通过动态规划的方法解决。下面我将详细介绍解决该问题的基本思想和步骤。

最长不下降子序列问题的基本思想是利用动态规划的思想,通过构建一个辅助数组来记录以每个元素结尾的最长不下降子序列的长度。通过遍历整个序列,不断更新辅助数组的值,最终得到最长不下降子序列的长度。

具体步骤

创建一个辅助数组 d p dp dp,长度与原始序列相同,用于记录以每个元素结尾的最长不下降子序列的长度。
初始化辅助数组 d p dp dp的所有元素为 1 1 1,表示每个元素本身就构成一个长度为 1 1 1的不下降子序列。
从第二个元素开始遍历原始序列,对于每个元素 n u m s [ i ] nums[i] nums[i],遍历其前面的所有元素 n u m s [ j ] nums[j] nums[j] j j j从0到 i i i- 1 1 1)。
在内层循环中,如果nums[ i i i]大于等于nums[ j j j],说明可以将 n u m s [ i ] nums[i] nums[i]加入到以 n u m s [ j ] nums[j] nums[j]结尾的不下降子序列中,此时更新 d p dp dp[ i i i]为 d p dp dp[ j j j]+ 1 1 1
在每次更新 d p dp dp[ i i i]时,同时更新一个全局变量 m a x x maxx maxx,用于记录最长不下降子序列的长度。
最后返回 m a x x maxx maxx作为结果。
例如,对于序列[ 3 3 3, 4 4 4, 2 2 2, 8 8 8, 5 5 5, 1 1 1],按照上述步骤进行计算:

  • 初始化辅助数组 d p dp dp为[ 1 1 1, 1 1 1, 1 1 1, 1 1 1, 1 1 1, 1 1 1]。
  • 从第二个元素开始遍历,对于元素 4 4 4,遍历前面的元素 3 3 3,由于 4 4 4大于 3 3 3,所以可以将 4 4 4加入到以 3 3 3结尾的不下降子序列中,此时更新 d p dp dp为[ 1 1 1, 2 2 2, 1 1 1, 1 1 1, 1 1 1, 1 1 1]。
  • 对于元素 2 2 2,遍历前面的元素 3 3 3 4 4 4,由于 2 2 2小于 3 3 3 4 4 4,无法构成不下降子序列,所以 d p dp dp保持不变。
  • 对于元素 8 8 8,遍历前面的元素 3 3 3 4 4 4 2 2 2,由于 8 8 8大于 3 3 3 4 4 4 2 2 2,可以将 8 8 8加入到以 2 2 2结尾的不下降子序列中,此时更新 d p dp dp为[ 1 1 1, 2 2 2, 1 1 1, 3 3 3, 1 1 1, 1 1 1]。
  • 对于元素 5 5 5,遍历前面的元素 3 3 3 4 4 4 2 2 2 8 8 8,由于 5 5 5大于 2 2 2 4 4 4,可以将 5 5 5加入到以 2 2 2结尾的不下降子序列中,此时更新 d p dp dp为[ 1 1 1, 2 2 2, 1 1 1, 3 3 3, 2 2 2, 1 1 1]。
  • 对于元素 1 1 1,遍历前面的元素 3 3 3 4 4 4 2 2 2 8 8 8 5 5 5,由于 1 1 1小于所有前面的元素,无法构成不下降子序列,所以 d p dp dp保持不变。
  • 最终得到辅助数组 d p dp dp为[ 1 1 1, 2 2 2, 1 1 1, 3 3 3, 2 2 2, 1 1 1],最长不下降子序列的长度为 3 3 3

总结: 最长不下降子序列问题通过动态规划的思想,利用辅助数组记录以每个元素结尾的最长不下降子序列的长度,从而得到最长不下降子序列的长度。这种方法的时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中 n n n是序列的长度。

A C 代码

#include<bits/stdc++.h>
#define N 1001
typedef long long ll;
using namespace std;
long long k,n,q,m,maxx=-1,a[N],f[N],c[N];
int main() {
    
    
	cin >>n;
	for(int i=1; i<=n; i++)
		cin >>a[i];
	for(int i=1; i<=n; i++) {
    
    
		f[i]=1;
		for(int j=1; j<i; j++)
			if(a[j]<=a[i] && f[j]+1>f[i])
				f[i]=f[j]+1;
		if(f[i]>maxx) {
    
    
			maxx=f[i];
			k=i;
		}
	}
	printf("%d",maxx);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/DUXS11/article/details/132270411