F - Zero Remainder Sum - 四维动态规划
题意:
给你n行每行m个元素 每行可以选择不超过(m/2) 个元素 最后将选择的元素 加到一起 余数为零的最大和
思路:
四维dp dp[i][j][w][u] 代表 第i行 到第j个元素 已经选了w个元素 余数为u 的最大和
第j个数 由第j-1个数转移过来 每次转移 w值也相应变化 类似01背包 取与不取 这题要多一个余数处理(而余数也恰恰是核心) 每次取了余数就会改变(u + a[i][j])%k 对于每个余数 更新当前状态最大值
然后还要加一个处理 因为有i行 前一行的相应余数时的最大值 应该转移给下一行 用dp[i + 1][0][0][ii] = max(dp[i][j][w][ii], dp[i + 1][0][0][ii]);
#include <bits/stdc++.h> #define ll long long #define pi acos(-1) #define F ios::sync_with_stdio(false), cin.tie(0) using namespace std; const int mod = 1e9 + 7; const int N = 1e6 + 10; int n, m, k, dp[80][80][80][80], a[80][80];//不用开ll 否则会MLE int main() { F; cin >> n >> m >> k; memset(dp, -1, sizeof(dp));//开始赋值为-1 表示没更新过 dp[1][0][0][0] = 0;//起始转移点必须为0 for(ll i = 1; i <= n; i++){ for(ll j = 1; j <= m; j++){ cin >> a[i][j]; } } for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ //min(j, m/2)的处理是因为 才选到第j个元素所以已选元素不可能比j大 且题目要求每行选择的元素 小于m/2 for(int w = 0; w <= min(j, m / 2); w++){ for(int u = 0; u < k; u++){ //有循环 dp[i][j][w][u]的值改变 要用max 若果是一次直接等于dp[i][j-1][w][u]也可 dp[i][j][w][u] = max(dp[i][j - 1][w][u], dp[i][j][w][u]); //w不能是0 应为w-1就会变成负数 没意义 要判断前一个有没有被更新过 //如果没被更新过说明之前不存在那样的余数的情况就不能往下更新 if(w && dp[i][j - 1][w - 1][u] != -1)//往下更新 dp[i][j][w][(u + a[i][j]) % k] = max(dp[i][j][w][(u + a[i][j]) % k], dp[i][j - 1][w - 1][u] + a[i][j]); } for(int ii = 0; ii < k; ii++){//第一层取相应余数时的最大值转移给下一层 //对于不同的k都可能为最大所以放到这 且用max dp[i + 1][0][0][ii] = max(dp[i][j][w][ii], dp[i + 1][0][0][ii]); } } } } //最后前n+1行 第0个元素 该行选择0个数 余数为0的最大值就是 答案值 cout << dp[n + 1][0][0][0] << endl; return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统