hdu1257 动态规划求最大递增子序列(LIS)长度


前言

这次是的代码自己思考的占了90%,有进步的一匹,感觉自己又可以了,现在已经基本掌握了动态规划的基本思想,加油!!!


一、题目

传送门
在这里插入图片描述

二、求LIS方法

1.利用最长公共子序列LCS求LIS

例如要求A={5,6,7,4,2,8,3}的LIS,对A排序str1={2,3,4,5,6,7,8},所以要求A的LIS,其实就是求A和str1的最长公共子序列
求LCS方法就不再写一遍了,之前写过
LCS求法

2.用DP写LIS

#include<iostream>
#include<stdio.h>
#include<string.h> 
using namespace std;
int dp[1005];
int a[1005];

//思路:
/*
dp[i]存前i个数中的最大递增子序列(LIS)长度;
首先初始化dp[0]=1;一个数的时候 LIS长度为1;
循环边输入边遍历,想找到一个LIS,可以从头看,
满足这个序列的第一层条件是要小于a[i],
然后定义的dp已经存储了最大长度,所以第二层条件就是找到最大的dp值
让其加一,得到的结果就是dp[i]的值 
这里我只输出了数组a中以每个数为结尾的LIS的长度,
再对dp用sort排序后输出dp[n-1]即可得到这个序列的LIS最大值 
*/ 

int main(){
	int n;

	while(cin>>n){
		cin>>a[0];
		memset(dp,0,sizeof(dp));
		dp[0]=1;
		for(int i=1;i<n;i++){
			cin>>a[i];
			int max=0;
			for(int j=0;j<i;j++){
				if(a[j]<a[i]){
					if(max<dp[j]){
						max=dp[j];
					}
				}
			}
			dp[i]=max+1;
		}
		int ans=0;
		for(int i=0;i<n;i++){
			if(ans<dp[i])ans=dp[i];
		}
		cout<<ans<<endl;//输出LIS长度 
		
		
		int res=0;//以下程序用来逆序输出LIS中的元素 
		int j=0;
		for(int i=n-1;i>=0;i--){
			if(dp[i]==ans){
				res=a[i];
				cout<<res<<" ";
				j=i;
				break;
			}
		} 
		ans--;

		for(int i=n-1;i>=0;i--){
			if(dp[i]==ans&&a[i]<res){
				res=a[i];
				cout<<a[i]<<" ";
				ans--;
			}
		}

	}
}
//样例:(便于理解) 
/*
7
1 4 5 3 2 7 8
1 2 3 2 2 4 5

7
3 5 4 1 6 2 9
1 2 2 1 3 2 4 
*/  

三、本题解法

回看本题,不难看出,这题要求的是所有的最大递减子序列个数,以样例分析,首先是A1={389,300,299,170,158},即当前最大递减子序列,删除这些,剩余A2={207,155},一共两个,这里,你可能会想到,利用LIS求法,改改程序,求递减的,每求出一个删掉,再对剩余的求,记录个数,这样确实可以,但好麻烦。 所以这里有一个更简单的方法,那就是LIS长度就是这个题的答案,即上面的代码就可以AC。
分析一波:在系统A2中至少有一个数a大于A1中的某个数,不然,这个数a完全可以加到A1中,那么A1就不是最长递减子序列了,所以从每个拦截系统中取出一个数,一定可以构成一个递增子序列,如果这个递增子序列不是最长的,,那么可以从某个系统中拿出两个数c>d,放到递增子序列中明显不满足递增条件,所以LIS的长度就是这个题的答案。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,关于 HDU4992 所有原根的问题,我可以给出以下解答: 1. 首先,我们需要知道什么是原根。原根是指模 n 意义下,所有与 n 互质的数 a 的最小正整数 k 次幂对 n 取模的值覆盖了所有与 n 互质的数。简单来说,就是如果一个数 a 是模 n 意义下的原根,那么 a 的任何正整数次幂对 n 取模的值都不相同,且能覆盖所有与 n 互质的数。 2. 为了模 n 意义下的所有原根,我们需要先出与 n 互质的数的个数 phi(n)。phi(n) 可以使用欧拉函数出。 3. 然后,我们需要枚举模 n 意义下的所有数,判断它是否是原根。具体来说,对于每个 a,我们需要判断 a 的每个小于 phi(n) 的正整数次幂对 n 取模的值是否都不相同,且能覆盖所有与 n 互质的数。如果是,那么 a 就是模 n 意义下的原根。 4. 代码实现可以参考以下 Java 代码: ``` import java.util.*; public class Main { static int gcd(int a, int b) { return b == 0 ? a : gcd(b, a % b); } static int phi(int n) { int res = n; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) { n /= i; } } } if (n > 1) { res = res / n * (n - 1); } return res; } static int pow(int a, int b, int mod) { int res = 1; while (b > 0) { if ((b & 1) != 0) { res = res * a % mod; } a = a * a % mod; b >>= 1; } return res; } static boolean check(int a, int n, int phi) { for (int i = 1, j = pow(a, i, n); i <= phi; i++, j = j * a % n) { if (j == 1) { return false; } } return true; } public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNext()) { int n = scanner.nextInt(); int phi = phi(n); List<Integer> ans = new ArrayList<>(); for (int i = 1; i < n; i++) { if (gcd(i, n) == 1 && check(i, n, phi)) { ans.add(i); } } Collections.sort(ans); for (int x : ans) { System.out.print(x + " "); } System.out.println(); } } } ``` 其中,gcd 函数用于最大公约数,phi 函数用于欧拉函数,pow 函数用于快速幂模,check 函数用于判断一个数是否是原根。在主函数中,我们依次读入每个 n,出 phi(n),然后枚举模 n 意义下的所有数,判断它是否是原根,将所有原根存入一个 List 中,最后排序输出即可。 希望我的回答能够帮到你,如果你有任何问题,欢迎随时提出。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值