Description

给定一个大小为 \(n \times m\) 的矩阵,要求每行只能选取不超过一半的元素,使得所有选出元素的总和是 \(k\) 的倍数,且这个总和最大。求这个最大值。\(n,m,k \le 70\)

Solution

考虑 dp,对于每一行 \(i\),首先预处理出 \(f[i][j][l][res]\) 表示在第 \(i\) 行中,从前 \(j\) 个数中选择了 \(l\) 个数,和 \(\mod k = res\) 的最大和为多少。据此,我们可以对 \(f[i][*][*][res]\)\(\max\) 得到 \(g[i][res]\),即从第 \(i\) 行中选不超过一半的数,且满足总和 \(\mod k = res\) 的限制条件时,能够达到的最大的和是多少。

\(h[i][res]\) 表示考虑前 \(i\) 行,从里面选取若干个数(当然数量要合法),且满足总和 \(\mod k = res\) 的限制条件时,能够达到的最大的和是多少。利用 \(g[i][res]\) 显然可以轻松计算。

#include <bits/stdc++.h>
using namespace std;

#define dbg(x) cout<<#x<<" = "<<x<<", "
#define dbgn(x) cout<<#x<<" = "<<x<<endl

const int N = 75;

int a[N][N],n,m,k;
int f[N][N][N][N],g[N][N],h[N][N];

signed main()
{
    cin>>n>>m>>k;
    for(int i=1;i<=n;i++) 
    {
        for(int j=1;j<=m;j++)
        {
            cin>>a[i][j];
        }
    }
    memset(f,-1,sizeof f);
    memset(g,-1,sizeof g);
    memset(h,-1,sizeof h);
    for(int i=1;i<=n;i++)
    {
        f[i][0][0][0]=0;
        for(int j=1;j<=m;j++)
        {
            for(int r=0;r<k;r++) f[i][j][0][r]=f[i][j-1][0][r];
            for(int l=1;l<=j;l++)
            {
                for(int r=0;r<k;r++)
                {
                    int pos=(r-a[i][j]+100*k)%k;
                    f[i][j][l][r]=f[i][j-1][l][r];
                    if(f[i][j-1][l-1][pos]!=-1)
                    {
                        f[i][j][l][r]=max(f[i][j][l][r],f[i][j-1][l-1][pos]+a[i][j]);
                    }
                }
            }
        }
    }

    for(int i=1;i<=n;i++)
    {
        g[i][0]=0;
        for(int r=0;r<k;r++)
        {
            int ans=-1;
            for(int l=0;l<=m/2;l++)
            {
                ans=max(ans,f[i][m][l][r]);
            }
            g[i][r]=ans;
        }
    }
    

    h[0][0]=0;
    for(int i=1;i<=n;i++)
    {
        for(int r=0;r<k;r++)
        {
            for(int d=0;d<k;d++)
            {
                if(h[i-1][r]!=-1 && g[i][d]!=-1)
                {
                    h[i][(r+d)%k]=max(h[i][(r+d)%k],h[i-1][r]+g[i][d]);
                }
            }
        }
    }

    cout<<h[n][0]<<endl;
    return 0;
}

相关文章:

  • 2021-09-15
  • 2022-12-23
  • 2021-06-11
  • 2022-12-23
  • 2022-02-28
  • 2021-12-30
  • 2021-07-18
猜你喜欢
  • 2021-11-21
  • 2022-12-23
  • 2022-12-23
  • 2021-09-04
  • 2021-12-07
  • 2021-10-11
  • 2021-11-13
相关资源
相似解决方案