思路:
传统的dp:
dp[i][j] 表示到第i个位置为止,分成j段的最大值
dp[i][j] = max(dp[l][j-1] + (sum[i] - sum[l]) % p) 0<= l < i
优化的dp:
我们发现n很大,但是p很小
于是
dp[i][j] 表示sum取模p后为i,分成j段的最大值
dp[i][j] = max(dp[l][j-1] + (sum[i] - l) % p) 0<= l < p
代码:
#include<bits/stdc++.h> using namespace std; #define LL long long #define pb push_back #define mem(a, b) memset(a, b, sizeof(a)) const int N = 2e4 + 5; const int INF = 0x3f3f3f3f; int dp[105][55], a[N]; int main() { int n, p, k; scanf("%d%d%d", &n, &k, &p); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); a[i] += a[i-1]; a[i] %= p; } for (int i = 0; i < p; i++) { for (int j = 0; j <= k; j++) dp[i][j] = -INF; } dp[0][0] = 0; for (int i = 1; i <= n; i++) { for (int j = k; j >= 1; j--) { for(int l = 0; l < p; l ++) dp[a[i]][j] = max(dp[a[i]][j], dp[l][j-1] + ((a[i]-l)%p+p)%p); } } printf("%d\n",dp[a[n]][k]); return 0; }