codeforces1433F. Zero Remainder Sum

F. Zero Remainder Sum

题面及输入输出
input:

3 4 3
1 2 3 4
5 2 2 2
7 1 1 4

output:

24

input:

5 5 4
1 2 4 2 1
3 5 1 2 4
1 5 7 1 2
3 8 7 1 2
8 4 7 1 6

output

56

题意: 给定一个 n ∗ m n * m nm 的矩阵,每行最多选择 ⌊ m 2 ⌋ \lfloor\frac{m}{2}\rfloor 2m 个数,要求选择完整个矩阵之后选择的数的和最大,且和模 k k k 等于0。
思路: 可以比较容易想到用4维 ( d p [ x ] [ y ] [ c n t ] [ s u m M o d K ] ) (dp[x][y][cnt][sumModK]) (dp[x][y][cnt][sumModK]) 或者3维 d p [ x ] [ y ] [ s u m M o d K ] dp[x][y][sumModK] dp[x][y][sumModK] 的dp去表示状态。 ( d p [ x ] [ y ] [ c n t ] [ s u m M o d K ] ) (dp[x][y][cnt][sumModK]) (dp[x][y][cnt][sumModK]) 表示当前在处理 a [ x ] [ y ] a[x][y] a[x][y]这个位置的数,第 x x x 行已经选择了 c n t cnt cnt 个,此时的最大和 % k \%k %k 等于sumModK。转移就十分明显了: 1. 1. 1. 如果当前已经选择了 ⌊ m 2 ⌋ \lfloor\frac{m}{2}\rfloor 2m个数,那么就不能再选择 a [ x ] [ y ] a[x][y] a[x][y] ,此时 ( d p [ x ] [ y ] [ c n t ] [ s u m M o d K ] ) (dp[x][y][cnt][sumModK]) (dp[x][y][cnt][sumModK]) 可以转移到 d p [ x ] [ y + 1 ] [ c n t ] [ s u m M o d K ] dp[x][y + 1][cnt][sumModK] dp[x][y+1][cnt][sumModK] 2. 2. 2. 如果选择的数不足 ⌊ m 2 ⌋ \lfloor\frac{m}{2}\rfloor 2m 个数,那么 a [ x ] [ y ] a[x][y] a[x][y] 就可以转移到两种状态: d p [ x ] [ y + 1 ] [ c n t + 1 ] [ ( s u m M o d K + a [ x ] [ y ] ) % K ] dp[x][y + 1][cnt + 1][(sumModK + a[x][y]) \% K] dp[x][y+1][cnt+1][(sumModK+a[x][y])%K] d p [ x ] [ y + 1 ] [ c n t ] [ s u m M o d K ] dp[x][y + 1][cnt][sumModK] dp[x][y+1][cnt][sumModK] 分别对应取 a [ x ] [ y ] a[x][y] a[x][y]和不取两种情况。
那么答案的取值就是在处理完整个矩阵之后的模数为0的情况的Max
a n s = { x ∣ x = d p [ n ] [ m + 1 ] [ c n t ] [ 0 ] } , 0 ≤ c n t ≤ ⌊ m 2 ⌋ ans = \lbrace x| x = dp[n][m + 1][cnt][0]\rbrace ,0 \le cnt \le \lfloor\frac{m}{2}\rfloor ans={xx=dp[n][m+1][cnt][0]},0cnt2m

AC代码:

/*---------------------------------
 *File name: A.cpp
 *Creation date: 2020-10-21 19:16
 *-------------------------------*/
#pragma GCC diagnostic error "-std=c++11"
#include<bits/stdc++.h>
#define fi first
#define se second
#define pb push_back
#define LL long long
#define PII pair<int, int> 
using namespace std;
typedef int readtype;
const int maxn = 1e5 + 5;
const int inf = INT_MAX;
const LL mod = 1e9 + 7;

inline readtype read(){
	readtype X=0; bool flag=1; char ch=getchar();
	while(ch<'0'||ch>'9') {if(ch=='-') flag=0; ch=getchar();}
	while(ch>='0'&&ch<='9') {X=(X<<1)+(X<<3)+ch-'0'; ch=getchar();}
	if(flag) return X;
	return ~(X-1);
}

int dp[75][75][40][75];
int a[75][75];

int main(){
	int n = read(), m = read(), k = read();
	for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j)	a[i][j] = read();
	memset(dp, -0x3f3f3f3f, sizeof(dp));
	dp[1][1][0][0] = 0;
	for(int i = 1; i <= n; ++i){
		for(int j = 1; j <= m; ++j){
			for(int cnt = 0; cnt <= m / 2; ++cnt){
				for(int Mod = 0; Mod < k; ++Mod){
					//if(dp[i][j][cnt][Mod] == -1) continue;
					if(cnt != m / 2) dp[i][j + 1][cnt + 1][(Mod + a[i][j]) % k] = max(dp[i][j + 1][cnt + 1][(Mod + a[i][j]) % k], dp[i][j][cnt][Mod] + a[i][j]);
					dp[i][j + 1][cnt][Mod] = max(dp[i][j + 1][cnt][Mod], dp[i][j][cnt][Mod]);
				}
			}
			if(j == m) for(int cnt = 0; cnt <= m / 2; ++cnt) for(int Mod = 0; Mod < k; ++Mod) dp[i + 1][1][0][Mod] = max(dp[i + 1][1][0][Mod], dp[i][j + 1][cnt][Mod]);
		}
	}
	int Max = 0;
	for(int j = 0; j <= m / 2; ++j) Max = max(Max, dp[n][m + 1][j][0]);
	printf("%d\n", Max);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值