CF1433F

题意:

给定一个n*m的矩阵,每行最多取m/2个数,求取得的数的和的最大值,并且和能被k整除

很明显就是一个取与不取的背包问题,唯一个问题是每行的限制怎么实现,其实很简单,只要在一行结束的时候把取了其他个数的值全都归到0上,把限制重置掉就行

转移方程:dp[i][j][k]表示取到第i个格子(按行列顺序编号),本行取了j个数,目前模K的余数为k时取到的最大值

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

 

下附代码:

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 using namespace std;
 5 const int INF=0X3f3f3f3f;
 6 int dp[4901][36][75],a[75][75];
 7 int n,m,k;
 8 int ab(int x,int k){
 9     if (x>=0) return x%k;
10     else {
11         int ex=abs(x)/k+1;
12         return (x+ex*k)%k;
13     }
14 }
15 int main(){
16     memset(dp,-1,sizeof(dp));
17     scanf("%d%d%d",&n,&m,&k);
18     for (int i=1; i<=n; i++)
19         for (int j=1; j<=m; j++){
20             scanf("%d",&a[i][j]);
21         }
22     dp[0][0][0]=0;
23     for (int i=1; i<=n; i++){
24         for (int j=1; j<=m; j++){
25             int now=(i-1)*m+j;
26             for (int p=0; p<=m/2; p++)
27                 for (int t=0; t<k; t++)
28                     dp[now][p][t]=dp[now-1][p][t];
29             for (int p=m/2; p>=1; p--){
30                 for (int t=k-1; t>=0; t--){
31                     if (dp[now-1][p-1][ab(t-a[i][j],k)]!=-1)
32                     dp[now][p][t]=max(dp[now][p][t],dp[now-1][p-1][ab(t-a[i][j],k)]+a[i][j]);
33                 }
34             }
35         }
36         for (int j=m/2; j>=1; j--){
37             for (int p=k-1; p>=0; p--){
38                 dp[i*m][0][p]=max(dp[i*m][0][p],dp[i*m][j][p]);
39             }
40         }
41     }
42     int res=0;
43     for (int i=0; i<=m/2; i++){
44         res=max(res,dp[n*m][i][0]);
45     }
46     printf("%d\n",res);
47 }

 

posted @ 2020-11-23 16:33  我是菜狗QAQ  阅读(89)  评论(0编辑  收藏  举报