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
n∗m 的矩阵,每行最多选择
⌊
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={x∣x=dp[n][m+1][cnt][0]},0≤cnt≤⌊2m⌋
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;
}