A - Frog 1
大意
有块石头,第块石头的高度为。从石头跳到石头的花费是。
一只青蛙在石头上,每次可以跳步或步,请问跳到石头的最小代价是多少?
思路
设,为青蛙跳到第号石头时的最小代价。
每一个点都可以由前两个点转移而来,因此状态转移方程为:
边界可由定义得出:。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<int> a(n + 1), dp(n + 1, 0);
for(int i = 1; i <= n; i++) cin >> a[i];
auto cost = [&](int i, int j) -> int{
int ret = a[i] - a[j];
if(ret < 0) ret = -ret;
return ret;
};
dp[2] = cost(1, 2);
for(int i = 3; i <= n; i++)
dp[i] = min(dp[i - 1] + cost(i, i - 1), dp[i - 2] + cost(i, i - 2));
cout << dp[n] << endl;
return 0;
}
B - Frog 2
大意
有块石头,第块石头的高度为。从石头跳到石头的花费是。
一只青蛙在石头上,每次可以跳~步,请问跳到石头的最小代价是多少?
思路
和上一题一样,设,为青蛙跳到第号石头时的最小代价。
每一个点都可以由前个点转移而来(除了的情况),因此状态转移方程为:
边界为。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, k;
cin >> n >> k;
vector<int> a(n + 1), dp(n + 1, INF);
for(int i = 1; i <= n; i++) cin >> a[i];
auto cost = [&](int i, int j){
int ret = a[i] - a[j];
return (ret > 0? ret: -ret);
};
dp[1] = 0;
for(int i = 2; i <= n; i++){
for(int j = max(1ll, i - k); j < i; j++) dp[i] = min(dp[i], dp[j] + cost(i, j));
}
cout << dp[n] << endl;
}
C - Vacation
大意
有天时间和种活动。每天只能进行一个活动,且相邻两天不能做相同的活动。
第天做三种活动分别可以获得点快乐值,求这天里最大可以获得多少点快乐值。
思路
设为考虑到第天,且第天进行活动的最大值。
由于相邻两天不能做相同的活动,所以只能从另外两个状态中的最大值转移过来。、
因此,状态转移方程为:
边界为,答案为。
时间复杂度。
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n;
cin >> n;
vector<int> a(n + 1), b(n + 1), c(n + 1);
vector<int> dp1(n + 1, 0), dp2(n + 1, 0), dp3(n + 1, 0);
for(int i = 1; i <= n; i++) cin >> a[i] >> b[i] >> c[i];
for(int i = 1; i <= n; i++){
dp1[i] = max(dp2[i - 1], dp3[i - 1]) + a[i];
dp2[i] = max(dp1[i - 1], dp3[i - 1]) + b[i];
dp3[i] = max(dp1[i - 1], dp2[i - 1]) + c[i];
}
cout << max(dp1[n], max(dp2[n], dp3[n])) << endl;
}
D - Knapsack 1
大意
有件物品和一个承重量为千克的袋子。
第件物品的重量为千克,价值为元。
现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。
思路
经典01背包问题,按照01背包的解法做即可。
注意需要long long。
时间复杂度
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> w(n + 1), v(n + 1), dp(m + 1, 0);
for(int i = 1; i <= n; i++) cin >> w[i] >> v[i];
for(int i = 1; i <= n; i++)
for(int j = m; j >= w[i]; j--)
dp[j] = max(dp[j], dp[j - w[i]] + v[i]);
cout << dp[m] << endl;
return 0;
}
E - Knapsack 2
大意
有件物品和一个承重量为千克的袋子。
第件物品的重量为千克,价值为元。
现在要挑选一些物品装入袋子里,求选择的物品的最大总价值。
思路
很大,直接套用01背包计算,时间和空间肯定一定炸。
由于很小,我们可以转换思路,设为价值为 的最小重量,这样就不会炸了。
最后从大到小遍历,找到符合的直接输出。
时间复杂度,其中为的取值范围,
代码
#include <iostream>
#include <vector>
using namespace std;
#define int long long
const int INF = 0x3f3f3f3f;
signed main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
int n, m;
cin >> n >> m;
vector<int> w(n + 1), v(n + 1);
int sum = 0;
for(int i = 1; i <= n; i++){
cin >> w[i] >> v[i];
sum += v[i];
}
vector<int> dp(sum + 1, INF);
dp[0] = 0;
for(int i = 1; i <= n; i++)
for(int j = sum; j >= v[i]; j--)
dp[j] = min(dp[j], dp[j - v[i]] + w[i]);
for(int j = sum; j >= 0; j--)
if(dp[j] <= m){
cout << j << endl;
break;
}
return 0;
}
F - LCS
题意
给定两个字符串,输出它们的任意一个最长公共子序列。
思路
求LCS时将最优策略保存下来,用来表示状态是否和有关,来表示状态是否和有关。
根据和,就可以递归输出方案。
代码
#include <iostream>
#include <vector>
using namespace std;
int main(){
ios::sync_with_stdio(0);
cin.tie(0), cout.tie(0);
string x, y;
cin >> x >> y;
int n = x.size(), m = y.size();
vector<vector<int>> dp(n + 1, vector<int>(m + 1));
vector<vector<int>> f1(n + 1, vector<int>(m + 1));
vector<vector<int>> f2(n + 1, vector<int>(m + 1));
auto lcs = [&](string a, string b, int n, int m) -> void{
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
if(a[i - 1] == b[j - 1]){
dp[i][j] = dp[i - 1][j - 1] + 1;
f1[i][j] = 1;
f2[i][j] = 1;
}else if(dp[i - 1][j] > dp[i][j - 1]){
dp[i][j] = dp[i - 1][j];
f1[i][j] = 1;
}else{
dp[i][j] = dp[i][j - 1];
f2[i][j] = 1;
}
}
};
string ans = "";
auto dfs = [&](auto self, string a, string b, int i, int j) -> void{
if(i == 0 || j == 0) return;
self(self, a, b, i - f1[i][j], j - f2[i][j]);
if(a[i - 1] == b[j - 1]) ans.push_back(a[i - 1]);
};
lcs(x, y, n, m);
dfs(dfs, x, y, n, m);
cout << ans << endl;
}