CF1433F 矩阵选数

1 CF1433F 矩阵选数

2 题目描述

时间限制 \(1s\) | 空间限制 \(256M\)

给出一个大小为 \(n \times m\) 的整数矩阵 \(a\)。每一行可以选择不超过 \(\left\lfloor\frac{m}{2}\right\rfloor\) 个元素。你的任务是选择一些元素使得他们可以被 \(k\) 整除,并且他们的累加和最大。换句话说每一行你可以选择不超过一半的的元素,你要找出能被 \(k\) 整除的最大累加和。注意你可以选择零个元素,当然累加和就是零。

数据范围:\(1≤𝑛,𝑚,𝑘≤70\)

3 题解

我们发现,这道题中的约束条件大概是这两条:每行选取的数的个数不能超过 \(\dfrac{m}{2}\),总价格必须为 \(k\) 的倍数。由于数据范围出奇的小,我们可以考虑一个包含这两个约束条件的 \(dp\)。首先,我们肯定需要有前两维:分别表示当前考虑了前几行和当前行考虑了前几个数。其次,我们需要把这两个约束条件包括进去。第一个约束条件简单,只需要再加一维记录选取的个数即可。但是第二个约束条件就有些复杂了。在看到 \(k \le 70\) 这一奇怪的条件后,我们想到:可以在最后一维存储当前总价格对 \(k\) 取余所得结果。于是状态就明了了:\(dp_{i, j, x, l}\) 表示考虑前 \(i\) 行,第 \(i\) 行考虑前 \(j\) 个,当前行选取了 \(x\) 个,当前和对 \(k\) 取模的结果为 \(l\) 时所能得到的最大值。设计完状态,转移也就出来了:

\[dp_{i, j, x, l} = max(dp_{i, j-1, x, l}, dp_{i, j-1, x-1, (l - (Map_{i, j} \space mod \space k) + k) \space mod\space k}) \]

注意这里我们将 \(Map_{i, j}\) 先对 \(k\) 取了一次模,保证取模后的结果小于 \(k\),然后在减完当前数后加上 \(k\) 再模 \(k\),保证了全过程不会出现大于等于 \(k\) 的或者是负数的下标出现。

这里我们在每一行开头的地方需要从上一行的最后一个数转移过来,以衔接上之前所算出的值。

4 代码(空格警告):

#include <iostream>
#include <cstring>
using namespace std;
const int N = 71;
int n, m, k, maxn;
int Map[N][N];
int dp[N][N][N][N];
int main()
{
    memset(dp, -0x3f, sizeof(dp));
    cin >> n >> m >> k;
    for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) cin >> Map[i][j];
    for (int i = 1; i <= n; i++)
    {
        dp[i][0][0][0] = 0;
        for (int j = 0; j <= m/2; j++)
        {
            for (int l = 0; l < k; l++)
            {
                dp[i][0][0][l] = max(dp[i][0][0][l], dp[i-1][m][j][l]);
            }
        }
        for (int j = 1; j <= m; j++)
        {
            for (int x = 0; x <= m/2; x++)
            {
                for (int l = 0; l < k; l++)
                {
                    if (x == 0) dp[i][j][x][l] = dp[i][j-1][x][l];
                    else
                    {
                        dp[i][j][x][l] = max(dp[i][j-1][x][l], dp[i][j-1][x-1][(l-(Map[i][j] % k) + k) % k] + Map[i][j]);
                    }
                }
            }
        }
    }
    for (int i = 0; i <= m/2; i++) maxn = max(maxn, dp[n][m][i][0]);
    cout << maxn;
    return 0;
}

欢迎关注我的公众号:智子笔记

posted @ 2021-03-31 15:20  David24  阅读(124)  评论(0编辑  收藏  举报