[acwing]1047.糖果
/*
dp[i][j] 表示只考虑前 i 件物品,模 k 余 j 的最大价值
如果不取第 i 件物品,dp[i][j] = dp[i - 1][j]
如果取第 i 件物品,dp[i][j] = dp[i - 1][((j - v[i]) % k + k) % k] + v[i]
遍历顺序 i[1, n],j[0, k - 1]
无需初始化
dp[n][0]
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 110;
int n, k;
int v[N];
int dp[N][N];
int main()
{
scanf("%d%d", &n, &k);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++)
for (int j = 0; j <= k - 1; j++) {
dp[i][j] = dp[i - 1][j]; // 不取第 i 个物品
if (dp[i - 1][((j - v[i]) % k + k) % k] != 0) // 取第 i 个物品,看之前有没有值与 v[i] 相加模 k 等于 j
dp[i][j] = max(dp[i - 1][j], dp[i - 1][((j - v[i]) % k + k) % k] + v[i]);
else if (v[i] % k == j) // 如果找不到,说明不能在原来的基础上进一步增大,再判断只有 v[i] 自身能否满足模 k 等于 j
dp[i][j] = max(dp[i - 1][j], v[i]);
}
printf("%d", dp[n][0]);
return 0;
}
[acwing]1234.倍数问题
/*
这道题结合了 [acwing]1047.糖果 和 [acwing]1050.鸣人的影分身
dp[i][j][k] 表示只考虑前 i 个物品,其总价值模 m 余 j,且个数为 k 的最大价值
如果不选第 i 个物品,dp[i][j][k] = dp[i - 1][j][k]
如果选第 i 个物品,dp[i][j][k] = dp[i - 1][((j - v[i]) % m + m) % m][k - 1] + v[i]
遍历顺序 i[1, n],j[0, m - 1],k[0, 3]
无需初始化
目标 dp[n][0][3]
由于 n 过大会爆内存,需优化
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010, M = 1010;
int n, m;
int v[N];
int dp[N][M][4];
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) scanf("%d", &v[i]);
for (int i = 1; i <= n; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k <= 3; k++) {
int &u = dp[i][j][k];
u = dp[i - 1][j][k];
if (k - 1 >= 0) {
if (dp[i - 1][((j - v[i]) % m + m) % m][k - 1] > 0)
u = max(u, dp[i - 1][((j - v[i]) % m + m) % m][k - 1] + v[i]);
else if (v[i] % m == j)
u = max(u, v[i]);
}
}
printf("%d", dp[n][0][3]);
return 0;
}
/*
mod[i] 存模 m 余 i 的数
新的 v 数组只存模 m 余 i 前三大的数
*/
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010, M = 1010;
int n, m;
int v[N], idx = 1;
vector<int> mod[M];
int dp[3 * M][M][4];
bool cmp(const int &lhs, const int &rhs)
{
return lhs > rhs;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
scanf("%d", &v[i]);
mod[v[i] % m].push_back(v[i]);
}
for (int i = 0; i < m; i++) sort(mod[i].begin(), mod[i].end(), cmp);
for (int i = 0; i < m; i++) {
for (int j = 0; j < 3 && j < mod[i].size(); j++)
v[idx++] = mod[i][j];
}
for (int i = 1; i <= idx - 1; i++)
for (int j = 0; j < m; j++)
for (int k = 0; k <= 3; k++) {
int &u = dp[i][j][k];
u = dp[i - 1][j][k];
if (k - 1 >= 0) {
if (dp[i - 1][((j - v[i]) % m + m) % m][k - 1] > 0)
u = max(u, dp[i - 1][((j - v[i]) % m + m) % m][k - 1] + v[i]);
else if (v[i] % m == j)
u = max(u, v[i]);
}
}
printf("%d", dp[idx - 1][0][3]);
return 0;
}