程序设计思维与实践 Week10 作业

A - 签到题

题意

给定两个数 n n n m m m,输出 n n n经过若干次乘2或乘3后转换为 m m m的次数

解题思路

首先判断m是否能被n整除,如果能够整除,将m除以n,之后进行循环,每次对m除以2或者除以3,直到m=1为止,若某次循环m没有除以2或3,即次数没有改变,说明无法转换。

代码

#include <iostream>
using namespace std;
int main(){
	int n, m;
	cin >> n >> m;
	if(m % n)
		cout << -1 <<endl;
	else{
		m /= n;
		int ans = 0;
		while(m != 1){
			int t = ans;
			if(m % 2 == 0){
				ans++;
				m /= 2;
			}else if(m % 3 == 0){
				ans++;
				m /= 3;
			}
			if(t == ans){
				cout << -1 << endl;
				break;
			}
		}
		if(m == 1) cout << ans << endl;
	}
	return 0;
}

B - LIS & LCS

题意

给定两个序列A和B。
求序列A的LIS和序列AB的LCS的长度。

解题思路

这道题可以分为两个部分,求取最长上升子序列和求取最长公共子序列。
LIS:

  • 状态:定义 f i f_i fi 表示以 A i A_i Ai 为结尾的最长上升序列的方程。
  • 初始化: f 1 = 1 f_1 = 1 f1=1
  • 转移过程: f i = m a x { f j   ∣   j < i ∧ A j < A i } f_i = max\{f_j\ |\ j<i \land A_j<A_i \} fi=max{fj  j<iAj<Ai}
  • 输出答案: m a x { f i   ∣   i ∈ [ 1 , n ] } max\{f_i\ |\ i\in[1, n] \} max{fi  i[1,n]}

LCS:

  • 状态: 定义 f i , j f_{i,j} fi,j表示 A 1 , A 2 , . . . , A i A_1,A_2,...,A_i A1,A2,...,Ai B 1 , B 2 , . . , B j B_1,B_2,..,B_j B1,B2,..,Bj的LCS长度
  • 初始化: f 1 , 0 = f 0 , 1 = f 0 , 0 = 0 f_{1,0} = f_{0,1}=f_{0,0}=0 f1,0=f0,1=f0,0=0
  • 转移方程: f i , j = { f i − 1. j − 1 + 1 A i = B j m a x { f i − 1 , j , f i , j − 1 } 其 他 f_{i,j} = \begin{cases} f_{i-1.j-1}+1 & A_i = B_j\\ max\{f_{i-1,j},f_{i,j-1}\} & 其他 \end{cases} fi,j={fi1.j1+1max{fi1,j,fi,j1}Ai=Bj
  • 输出答案: f n , m f_{n,m} fn,m

代码

#include <iostream>
#include <algorithm>
using namespace std;
int A[5010], B[5010];
int f[5010];
int f1[5010][5010];
int main(){
	int n, m;
	cin >> n >> m;
	for(int i = 1; i <= n; ++i)
		cin >> A[i];
	for(int i = 1; i <= m; ++i)
		cin >> B[i];
	f[1] = 1;
	for(int i = 2; i <= n; ++i){
		int maxx = 0;
		for(int j = 1; j < i; ++j){
			if(A[j] < A[i] && f[j] > maxx)
				maxx = f[j];
		}
		f[i] = maxx + 1;
	}
	int maxx = 0;
	for(int i = 1; i <= n; ++i)
		if(f[i] > maxx) maxx = f[i];
	cout << maxx << ' ';
	f1[1][0] = f1[0][1] = f1[0][0] = 0;
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			if(A[i] == B[j]) f1[i][j] = f1[i-1][j-1] + 1;
			else f1[i][j] = max(f1[i-1][j], f1[i][j-1]);
		}
	}
	cout << f1[n][m];
	return 0;
}

C - 拿数问题 II

题意

给 n 个数,每一步能拿走一个数,比如拿第 i 个数, Ai = x,得到相应的分数 x,但拿掉这个 Ai 后,x+1 和 x-1 (如果有 Aj = x+1 或 Aj = x-1 存在) 就会变得不可拿(但是有 Aj = x 的话可以继续拿这个 x)。求最大分数。

解题思路

我们使用 c n t [ i ] cnt[i] cnt[i] 表示数 i i i 的个数

  • 状态: d p [ i ] dp[i] dp[i] 表示只考虑拿区间 [ 1 , i ] [1,i] [1,i] 的数,能拿到的最大分数
  • 初始化: d p [ 1 ] = c n t [ 1 ] , d p [ 2 ] = m a x ( d p [ 1 ] ,   2 ∗ c n t [ 2 ] ) dp[1] = cnt[1], dp[2] = max(dp[1],\ 2*cnt[2]) dp[1]=cnt[1],dp[2]=max(dp[1], 2cnt[2])
  • 转移方程: d p [ i ] = m a x ( d p [ i − 1 ] ,   d p [ i − 2 ] + c n t [ i ] ∗ i ) dp[i] = max(dp[i-1],\ dp[i-2]+cnt[i]*i) dp[i]=max(dp[i1], dp[i2]+cnt[i]i)
  • 输出答案: d p [ m a x ( i ) ] dp[max(i)] dp[max(i)]

代码

#include <iostream>
#include <algorithm>
using namespace std;
long long dp[100010];
long long cnt[100010];
int main(){
	int n, maxx = 0;
	cin >> n;
	for(int i = 0; i < n; ++i){
		int temp;
		cin >> temp;
		cnt[temp]++;
		if(temp > maxx) maxx = temp;
	}
	dp[1] = cnt[1];
	dp[2] = max(cnt[2] * 2, dp[1]);
	for(int i = 3; i <= maxx; ++i)
		dp[i] = max(dp[i-1], dp[i-2] + cnt[i] * i);
	cout << dp[maxx] << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值