Codeforces-1433F-Zero Remainder Sum

Zero Remainder Sum

题目链接

^-^

题目大意

相信看题解的都是看懂题目的(主要是懒得打字了

解题思路

一看就是dp题,我们按照一行一行从上到下、从左到右的顺序来求解、我们用dp[i][j][cnt][rem] 表示选到第i行、第j列并且第i行已经选择cnt个元素且余数为rem的时候的最大值。那么现要进行初始化,dp[0][0][0][0]=0,其余的都是-inf

然后就是递归式

对于每一行的每一列的元素假设为a[i][j]来说,都有选择(前题是cnt+1<=m/2)或者不选的可能。如果选择这个的话,就向后更新,即

    nrem=(rem+a[i][j])%k;
    dp[i][j+1][cnt+1][nrem]=max(dp[i][j+1][cnt+1][nrem],dp[i][j][cnt][rem]+a[i][j]);

如果不选择的话,就有

    dp[i][j+1][cnt][nrem]=max(dp[i][j+1][cnt][nrem],dp[i][j][cnt][rem]+a[i][j]);

但是当我们遍历到最后一个元素的时候,就有些不同,因为我们第i行的答案受第i-1行的影响(从上到下),因此我们遍历到每一行的最后一个元素的时候,要将其更新到下一行而不是再外后,除此之外,如果这个值选取的话,对下行的cnt值并没有影响,因此也就不用进行cnt+1次操作。最后的答案就是dp[n][0][0][0]

#include<bits/stdc++.h>
using namespace std;
const int maxn=70;
int dp[maxn][maxn][maxn][maxn];
int a[maxn][maxn];
const int inf=-0x3f3f3f;
int main()
{
    int n,m,k;
    cin>>n>>m>>k;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            cin>>a[i][j];
        }
    }
    for(int i=0;i<maxn;i++)
    {
        for(int j=0;j<maxn;j++)
        {
            for(int cnt=0;cnt<maxn;cnt++)
            {
                for(int rem=0;rem<maxn;rem++)
                {
                    dp[i][j][cnt][rem]=inf;
                }
            }
        }
    }
    dp[0][0][0][0]=0;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            for(int cnt=0;cnt<m/2+1;cnt++)
            {
                for(int rem=0;rem<k;rem++)
                {
                    if(dp[i][j][cnt][rem]==-inf) continue;
                    int ni=(j==m-1?i+1:i);
                    int nj=(j==m-1?0:j+1);
                    if(i!=ni) //显示不选择的情况 表示切换到下一行 
                    {
                        dp[ni][nj][0][rem]=max(dp[ni][nj][0][rem],dp[i][j][cnt][rem]); 
                    } 
                    else{
                        dp[ni][nj][cnt][rem]=max(dp[ni][nj][cnt][rem],dp[i][j][cnt][rem]); 
                    }
                    if(cnt+1<=m/2)
                    {
                        int nrem=(a[i][j]+rem)%k;
                        if(i!=ni)
                        {
                            dp[ni][nj][0][nrem]=max(dp[ni][nj][0][nrem],dp[i][j][cnt][rem]+a[i][j]);
                        }
                        else{
                            dp[ni][nj][cnt+1][nrem]=max(dp[ni][nj][cnt+1][nrem],dp[i][j][cnt][rem]+a[i][j]);
                        }
                    }
                }
            }
        }
    }
    cout<<dp[n][0][0][0]<<endl;
    return 0;
} 
原文地址:https://www.cnblogs.com/tombraider-shadow/p/13854238.html