思路
我们设为在区间内的答案,这个答案从内个小区间转移而来。那么转移方程就是
要注意的地方
- 区间类型有关动态规划的问题一般可以用区间DP合并来解决
- 注意枚举的中间点的的范围,只有大于这样才能保证从个区间转移而来
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 55 * 2;
const int M = 15;
const int MOD = 10;
const int INF = 0x3f3f3f3f;
int n, m, arr[N], sum[N];
int dp_min[N][N][M];
int dp_max[N][N][M];
inline int Min(int x, int y) {
return x <= y ? x : y;
}
inline int Max(int x, int y) {
return x >= y ? x : y;
}
int read() {
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {
if (ch == '-') w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9') {
s = s * 10 + ch - '0';
ch = getchar();
}
return s * w;
}
void write(int x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int main(int argc, char const *argv[]) {
n = read(), m = read();
for (register int i = 1; i <= n; ++i)
arr[i] = read(), sum[i] = sum[i - 1] + arr[i];
for (register int i = n + 1; i <= 2 * n; ++i)
arr[i] = arr[i - n], sum[i] = sum[i - 1] + arr[i];
for (register int len = 1; len <= 2 * n; ++len) {
for (register int l = 1; l + len - 1 <= 2 * n; ++l) {
int r = l + len - 1;
for (register int num = 1; num <= m; ++num) {
if (num == 1) {
dp_min[l][r][num] = ((sum[r] - sum[l - 1]) % MOD + MOD) % MOD;
dp_max[l][r][num] = ((sum[r] - sum[l - 1]) % MOD + MOD) % MOD;
} else {
dp_min[l][r][num] = INF;
dp_max[l][r][num] = -INF;
for (register int k = l + num - 2; k < r; ++k) {
dp_min[l][r][num] = Min(dp_min[l][r][num],
dp_min[l][k][num - 1] * (((sum[r] - sum[k]) % MOD + MOD) % MOD));
dp_max[l][r][num] = Max(dp_max[l][r][num],
dp_max[l][k][num - 1] * (((sum[r] - sum[k]) % MOD + MOD) % MOD));
}
}
}
}
}
int ans_min = INF;
int ans_max = -INF;
for (register int l = 1; l + n - 1 <= 2 * n; ++l) {
int r = l + n - 1;
ans_min = Min(ans_min, dp_min[l][r][m]);
ans_max = Max(ans_max, dp_max[l][r][m]);
}
write(ans_min), putchar('\n');
write(ans_max), putchar('\n');
return 0;
}