T1:子序列相似度

本题难度中等,做法和编辑距离类似,用 dp[i][j] 表示 s 的长为 i 的前缀和 t 的长为 j 的前缀的最大相似度

初值:

dp[0][0]=0

转移:

dp[i][j]={dp[i1][j]dp[i][j1]dp[i1][j1]+22526|sisj|

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); ++i)
using namespace std;
int dp[3005][3005];
inline void chmax(int& x, int y) { if (x < y) x = y; }
int main() {
int n, m;
cin >> n >> m;
string s, t;
cin >> s >> t;
rep(i, n)rep(j, m) {
int now = 0;
chmax(now, dp[i][j+1]);
chmax(now, dp[i+1][j]);
chmax(now, dp[i][j]+225-26*abs(s[i]-t[j]));
dp[i+1][j+1] = now;
}
cout << dp[n][m] << '\n';
return 0;
}

T2:积木大赛2

本题难度较大,因为操作次数和前一个高度差值有关,所以如果要改变某个积木,那么改成和上一个积木高度一样是最好的。因为这样可以将两个积木看成一块积木同时操作,一定不会让操作次数变多。

  1. k=0 时,每一块积木对答案的贡献为 max(0,hihi1)

  2. k0 时,修改等价于删除,修改 k 次等价于删除 k 次,意味着留下 nk 块积木

dp[i][j] 表示上一块留下积木 i且共留下 j 块积木时的最少操作次数

初值:

dp[0][0]=0,其他 dp=

转移:

dp[i][j]=minx=0i1{dp[x][j1]+max(0,hihx)}

代码实现
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 1; i <= (n); ++i)
using namespace std;
using ll = long long;
ll dp[305][305];
inline void chmin(ll& x, ll y) { if (x > y) x = y; }
int main() {
int n, k;
cin >> n >> k;
if (n == k) {
puts("0");
return 0;
}
vector<int> h(n+1);
rep(i, n) cin >> h[i];
memset(dp, 0x3f, sizeof dp);
dp[0][0] = 0;
rep(i, n) {
rep(j, n-k) {
for (int x = 0; x < i; ++x) {
chmin(dp[i][j], dp[x][j-1]+max(0, h[i]-h[x]));
}
}
}
ll ans = 1e18;
rep(i, n) chmin(ans, dp[i][n-k]);
cout << ans << '\n';
return 0;
}