Codeforces 1433F. Zero Remainder Sum (线性DP)

Description在这里插入图片描述
Examples

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

Solution
dp[i][d][k] : 在第 i i i行选择 d d d个数( d + d < = m d+d<=m d+d<=m)的和 %   m o d = = k \%~mod == k % mod==k 的最大值
dp2[i][k]: 在第 i i i行选择若干数(不大于 m / 2 m/2 m/2)的和 %   m o d = = k \%~mod == k % mod==k 的最大值
res[i][k]: 前 i i i行选择若干数(不大于 m / 2 m/2 m/2)的和 %   m o d = = k \%~mod == k % mod==k 的最大值

故res[n][0]的值即为所求

Code

const int maxn = 70 + 7;
const int inf = 1e9 + 7;
int mp[maxn][maxn];
int dp[maxn][maxn][maxn], dp2[maxn][maxn];
int res[maxn][maxn];
int main(){
	int n,m,mod;scanf("%d%d%d",&n,&m,&mod);
	memset(dp,-1,sizeof(dp));
	memset(dp2,-1,sizeof(dp2));
	for(int i = 1;i <= n;++i) for(int j = 1;j <= m;++j) scanf("%d",&mp[i][j]);
	for(int i = 1;i <= n;++i) {
		dp[i][0][0] = 0;
		for(int j = 1;j <= m;++j) {
			for(int d = min(j,m/2);d >= 1;--d) {
				for(int k = 0;k < mod;++k) {
					if(dp[i][d-1][k] != -1) dp[i][d][(k+mp[i][j])%mod] = 
					max(dp[i][d][(k+mp[i][j])%mod], dp[i][d-1][k] + mp[i][j]);
				}
			}
		}
		for(int k = 0;k < mod;++k) {
			for(int d = 0;d + d <= m;++d) {
				if(dp[i][d][k] != -1) dp2[i][k] = max(dp2[i][k], dp[i][d][k]);
			}
		}

	}
	memset(res,-1,sizeof(res));
	res[0][0] = 0;
	for(int i = 1;i <= n;++i) {
		res[i][0] = max(res[i][0],0);
		for(int k1 = 0;k1 < mod;++k1) {
			for(int k2 = 0;k2 < mod;++k2) {
				if(res[i-1][k1] != -1 && dp2[i][k2] != -1) res[i][(k1+k2)%mod] = 
				max(res[i][(k1+k2)%mod], res[i-1][k1] + dp2[i][k2]);
			}
		}
	}
	printf("%d\n", max(0,res[n][0]));
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值