

1.朴素dp,超时
/*
组合问题求最优解:背包问题
闫氏分析法:f(i, j, k):一个限制条件,一个维度
1.状态表示:从前i个数中取j个数模K的值为k的和的最大值
答案就是:f(n, 3, 0);
2.状态计算:01背包,取或者不取第i个数
取:f(i - 1, j, k);
不取:f(i - 1, j, ((k - a[i]) % k + K) % K)) + a[i]; // 注意,C++中取模%可能为负数
f(i, j, k) = max(f(i - 1, j, k), f(i - 1, j, ((k - a[i]) % k + K) % K)) + a[i]);
3.已知(x + A) % K = k,求 x % K
解:x + A = k + PK;
x = k - A + PK; // 即 x 与 k - A 同余
x % K = (k - A) % K;
4.时间计算
1e5 * 4 * 1e3 = 4 * 1e8, 超时1s
5.优化
*/
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 1e5 + 10;
int n, K, a[N];
int main()
{
cin >> n >> K;
for(int i = 1; i <= n; i++) cin >> a[i];
// 初始化
vector<vector<vector<int>>> dp(n + 1, vector<vector<int>>(4, vector<int>(K, -2e9)));
// 前n个数选0个数模k的值为0的和最大值都为0
for(int i = 0; i <= n; i++) dp[i][0][0] = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= 3; j++)
for(int k = 0; k < K; k++)
dp[i][j][k] = max(dp[i-1][j][k], dp[i-1][j-1][((k - a[i]) % K + K) % K] + a[i]);
cout << dp[n][3][0] << endl;
return 0;
}
2.dp加贪心优化,AC