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<i∧Aj<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={fi−1.j−1+1max{fi−1,j,fi,j−1}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], 2∗cnt[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[i−1], dp[i−2]+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;
}