1. 程式人生 > 實用技巧 >Codeforces-1433F-Zero Remainder Sum

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