F. Zero Remainder Sum(Codeforces Round #677 (Div. 3))

题目来源

https://codeforces.ml/contest/1433/problem/F

题意分析

  题目意思的大致可以描述为,给一个n*m的方阵,并且给一个k,每一行我们最多只能取m/2个数字,问在这个方阵之中,在我们取的所有数的和为k的倍数的情况下,这个数和最大是多少?

思路分析

  数据范围不大,想到dp。
  首先对每一行进行处理,因为每一行都是独立的。我们要处理出余数从0 - k-1的数的和的最大值,所以开一个数组pre。又因为每一行有长度的限制,所以我们就加一维来规范我们取的长度。所有pre是一个三维的数组,pre[i][j][l]表示的是第i行我们取了l个数,此时的数和对k的余数为j的最大值,这个数组我们可以用一个四重的循环进行初始化。分别循环他的行数,每行数字的个数,长度以及余数。循环长度的时候一定要逆着走,这里应该与01背包中的原理是相同的,即保证每一个数只会被选择一次。
  那么根据上面的初始化,我们再将上面的数据映射到我们的dp数组之中。因为我们的dp数组表示的是第i行余数为j的最大值,所以要将长度那一维去掉。于是用一个两重循环初始化dp数组,求所有长度下某个余数的最大值。
  在dp数组被初始化之后,接下来将行与行之间的关系进行处理。即用一个k*k的循环,处理出在两行中取数字时候的各个余数的最大值。那么这样一直处理到第n行,ans[n][0]即是我们最终的答案。
  最后要提的是要注意所有数组的初始化,具体细节请见代码,其目的是为了排除一些不会出现的情况,不让其对最终答案产生影响。

code

 1 #include <bits/stdc++.h>
 2 
 3 #define INF 0x3f3f3f3f
 4 #define ll long long
 5 using namespace std;
 6 const int maxn = 105;
 7 
 8 int pre[maxn][maxn][maxn];
 9 int dp[maxn][maxn];
10 int ans[maxn][maxn];
11 int a[maxn][maxn];
12 int n, m, k;
13 
14 signed main(){
15     scanf("%d%d%d", &n, &m, &k);
16     for (int i=1; i<=n; i++){
17         for (int j=1; j<=m; j++) scanf("%d", &a[i][j]);
18     }
19     memset(pre, -INF, sizeof (pre));
20     for (int i=1; i<=n; i++) pre[i][0][0] = 0;
21 
22     for (int i=1; i<=n; i++){
23         int ln = m / 2;
24         for (int p=1; p<=m; p++){
25             for (int l=min(ln, p)-1; l>=0; l--){
26                 for (int j=0; j<k; j++){
27                     int tmp = a[i][p];
28                     pre[i][(j+tmp) % k][l+1] = max(pre[i][(j+tmp) % k][l+1], pre[i][j][l] + a[i][p]);
29 //                    cout << i << " " << (j + tmp) % k << " " << l + 1 << "  " << pre[i][(j+tmp) % k][l+1] << endl;
30                 }
31             }
32         }
33     }
34     memset(dp, -INF, sizeof (dp));
35     for (int i=1; i<=n; i++){
36         for (int j=0; j<k; j++){
37             for (int l=0; l<=m/2; l++){
38                 dp[i][j] = max(dp[i][j], pre[i][j][l]);
39             }
40         }
41     }
42 
43 //    for (int i=0; i<k; i++){
44 //        for (int j=0; j<=m/2; j++) printf("%d ", pre[1][i][j]);
45 //        printf("\n");
46 //    }
47 //    printf("---------------------------\n");
48 //    for (int i=1; i<=n; i++){
49 //        for (int j=0; j<k; j++)  printf("%d ", dp[i][j]);
50 //        printf("\n");
51 //    }
52 //    printf("\n");
53     memset(ans, -INF, sizeof (ans));
54     for (int i=0; i<k; i++) ans[1][i] = dp[1][i];
55 
56 
57     for (int i=2; i<=n; i++){
58         for (int j=0; j<k; j++){
59             for (int p=0; p<k; p++){
60                 int tmp = (j + p) % k;
61                 ans[i][tmp] = max(ans[i][tmp], ans[i-1][j] + dp[i][p]);
62             }
63         }
64     }
65 
66 //    for (int i=2; i<=n; i++){
67 //        for (int j=0; j<k; j++) printf("%d ", ans[i][j]);
68 //        printf("\n");
69 //    }
70 
71     printf("%d\n", ans[n][0]);
72 
73 
74     return 0;
75 }

 

 

 

posted @ 2020-10-21 22:38  Rain_island  阅读(185)  评论(0编辑  收藏  举报
Title