1. 程式人生 > 實用技巧 >[CF1433F] Zero Remainder Sum - dp

[CF1433F] Zero Remainder Sum - dp

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;
}