dp寒假训练
状态机模型
题目大意: 给定一个序列,可以删除以个value值为a的一个数,并获取a分,但是每选择一个value值为a的值,就会删除所有value等于 a - 1 和 a + 1 的值,求能获得的最高得分。
错解:从dp[i - 2] 的状态直接转移到dp[i]的状态
hack数据
5
4 2 3 2 5
如果是这一组数据的话得到的值为8,而实际上最大的值应该是9
错解dp转移过程
dp[2] = 2 * 2 = 4
dp[3] = 1 * 3 = 3
dp[2] -> dp[4] = dp[2] + dp[4] = 8
dp[3]->dp[5] = dp[3] + dp[5] = 8
然后从所有的dp序列中找到最大的取max
但是可以从dp[2] 转移到dp[5] = dp[2] + dp[5] = 9, 这样是最大的
正解:
状态表示:
dp[i][0]表示第i元素不取的最大值
dp[i][1]表示第i元素选取的最大值
状态转移:
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1])
dp[i][1] = max(dp[i][1], dp[i - 1][0] + cnt[i] * i)
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 100010;
typedef long long ll;
int n;
ll dp[N][2], cnt[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for(int i = 0, x; i < n; i++) {
cin >> x;
cnt[x]++;
}
for(int i = 1; i <= 100000; i++) {
dp[i][1] = max(dp[i][1], dp[i - 1][0] + cnt[i] * i);
dp[i][0] = max(dp[i - 1][0], dp[i - 1][1]);
}
cout << max(dp[100000][0], dp[100000][1]) << '\n';
return 0;
}
背包模型
连接: Codeforces Buns
状态表示:
dp[i][j] 表示从前个物品中选,体积为j的最大值
先进行对不需要消耗调料得的进行预处理,然后再进行多重背包,先枚举选择的数量,上限为a / b,在进行多重背包的时候,体积要从大到小进行枚举,相当于进行了一次01背包。
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1010, M = 15;
int n, m, c0, d0;
int dp[M][N * M];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n >> m >> c0 >> d0;
for(int i = c0; i <= n; i++) dp[0][i] = i / c0 * d0;
for(int i = 1; i <= m; i++) {
int a, b, c, d;
cin >> a >> b >> c >> d;
for(int k = 0; k * b <= a; k++)
for(int j = n; j >= k * c; j--)
dp[i][j] = max(dp[i][j], dp[i - 1][j - k * c] + k * d);
}
cout << dp[m][n] << '\n';
return 0;
}
LCIS
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 3010;
int n, m;
int a[N], b[N], dp[N][N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for(int i = 0; i < n; i++) cin >> a[i];
m = n;
for(int i = 0; i < m; i++) cin >> b[i];
int res = 0;
for(int i = 0; i < n; i++) {
int max_dp = 0;
for(int j = 0; j < m; j++) {
dp[i + 1][j + 1] = dp[i][j + 1];
if(b[j] < a[i] && max_dp < dp[i + 1][j + 1]) max_dp = dp[i + 1][j + 1];
if(a[i] == b[j]) dp[i + 1][j + 1] = max_dp + 1;
res = max(res, dp[i + 1][j + 1]);
}
}
cout << res << '\n';
return 0;
}