zoukankan      html  css  js  c++  java
  • [CF1433F] Zero Remainder Sum

    Description

    给定一个大小为 (n imes 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;
    }
    
    
  • 相关阅读:
    MEAN: AngularJS + NodeJS的REST API开发教程
    什么是MEAN全堆栈javascript开发框架
    fputcsv 导出excel,解决内存、性能、乱码、科学计数法问题
    React 高德地图画点画区域放大缩小
    React 拖动布局
    React+TypeScript搭建项目
    js 运算符优先级
    for...in 与 for...of
    前端面试点记录
    Vue 高德地图 路径规划 画点
  • 原文地址:https://www.cnblogs.com/mollnn/p/13878483.html
Copyright © 2011-2022 走看看