1433F - Zero Remainder Sum
1433F - Zero Remainder Sum
\(~~~~\)动态规划,\(dp[i][j][p][q]\)表示在第\(i\)行,第\(j\)列,已经在这一行选取了\(p\)个元素,且目前的元素和对\(k\)取模是\(q\)时的最大和,首先有\(dp[1][0][0][0]=0\)。可以采用递推的方式由当前状态向下一个状态递推,结果即\(dp[n+1][0][0][0]\)。
\(~~~~\)当更新到某个状态时,对下一列的状态进行递推:如果不选取\(a[i][j+1]\),有转移方程
\(~~~~\)\(dp[i][j+1][p][q] = max(dp[i][j+1][p][q], dp[i][j][p][q])\)
\(~~~~\)如果选取,有转移方程(p大于0并且\(dp[i][j][p-1][q]\)被更新过的前提下)
\(~~~~\)\(dp[i][j+1][p][(q+a[i][j+1])\%k] = max(dp[i][j+1][p][(q+a[i][j+1])\%k], dp[i][j][p-1][q]+a[i][j+1])\)
更新完下一列的状态后,对\(dp[i+1][0][0][0]\)更新,方法类似
\(~~~~\)\(dp[i+1][0][0][q] = max(dp[i+1][0][0][q], dp[i][j+1][p][q]) (0<q<k)\)
代码
#include<iostream>
#include<stdio.h>
#include<cstdio>
#include<string.h>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<cmath>
#define INF 0x3f3f3f3f
typedef long long ll;
using namespace std;
inline void read(int &p)
{
p=0;int flag=1;char c=getchar();
while(!isdigit(c)) {if(c=='-') flag=-1;c=getchar();}
while(isdigit(c)) {p=p*10+c-'0';c=getchar();}p*=flag;
}
int dp[80][80][80][80];
int a[80][80];
int main()
{
#ifdef LOCAL
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int m, n, k;
cin >> n >> m >> k;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
read(a[i][j]);
}
}
memset(dp, -1, sizeof(dp));
dp[1][0][0][0] = 0;
for(int i=1; i<=n; i++){
for(int j=0; j<m; j++){
for(int p=0; p<=min(j+1, m/2); p++){
for(int q=0; q<k; q++){
dp[i][j+1][p][q] = max(dp[i][j+1][p][q], dp[i][j][p][q]);
if(p && dp[i][j][p-1][q]!=-1){
dp[i][j+1][p][(q+a[i][j+1])%k] = max(dp[i][j+1][p][(q+a[i][j+1])%k], dp[i][j][p-1][q]+a[i][j+1]);
}
}
for(int q=0; q<k; q++){
dp[i+1][0][0][q] = max(dp[i+1][0][0][q], dp[i][j+1][p][q]);
}
}
}
}
cout << dp[n+1][0][0][0] << endl;
return 0;
}

浙公网安备 33010602011771号