CodeForces Div3.F - Zero Remainder Sum
阿新 • • 發佈:2020-10-21
CodeForces Div3.F - Zero Remainder Sum
題意
給定一個 \(n \times m\)的矩陣,你可以在每一行選擇不多於\(\frac{n}{2}\)個元素,使得整體選擇的元素的和模\(k\)為0,並且和越大越好。
\[1\leq n,m,k\leq 70\\ 1\leq a_{ij} \leq 70 \]分析
據說是一道標準的動態規劃問題。
令\(dp[x][y][cnt][rem]\)表示當前在\(i,j\),當前行已經選取了\(cnt\)個元素並且當前的餘數是\(rem\)
初始化\(dp\)為負無窮,\(dp[0][0][0][0] = 0\)
狀態轉移
\[dp[nx][ny][cnt][rem] = max(dp[nx][ny][cnt][rem],dp[x][y][cnt][rem]) 表示不取當前元素\\ dp[nx][ny][cnt + 1][(rem+a_{ij})\%k] = max(dp[nx][ny][cnt+1][(rem+a_{ij})\%k],dp[x][y][cnt][rem] + a_{ij}) 表示取當前元素 \]答案就是\(max(dp[n][0][0][0],0)\),這裡可以認為是最後一行的下一行的第一個元素
注意一下實現的時候直接套上四個\(for\)就行了
程式碼
const int M = 70; int a[M][M]; int dp[M][M][M][M]; int main() { int n = readint(); int m = readint(); int k = readint(); for (int i = 0; i < n; i++) for (int j = 0; j < m; j++) a[i][j] = readint(); memset(dp, -INF, sizeof dp); 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 nx = (j == m - 1 ? i + 1 : i); int ny = (j == m - 1 ? 0 : j + 1); if (i != nx) dp[nx][ny][0][rem] = max(dp[nx][ny][0][rem], dp[i][j][cnt][rem]); else dp[nx][ny][cnt][rem] = max(dp[nx][ny][cnt][rem], dp[i][j][cnt][rem]); if (cnt + 1 <= m / 2) { int nrem = (rem + a[i][j]) % k; if (i != nx) dp[nx][ny][0][nrem] = max(dp[nx][ny][0][nrem], dp[i][j][cnt][rem] + a[i][j]); else dp[nx][ny][cnt + 1][nrem] = max(dp[nx][ny][cnt + 1][nrem], dp[i][j][cnt][rem] + a[i][j]); } } } } } cout << max(0,dp[n][0][0][0]); }