洛谷 P1043 数字游戏 题解

思路

我们设\(dp(i)(j)(k)\)为在区间\([i, j]\)内的答案,这个答案从\([i,j]\)\(m\)个小区间转移而来。那么转移方程就是
\[ dp(i)(j)(k) = 1 \ (k == 1) \\ dp(i)(j)(k) = max \{ dp(i)(p)(k - 1) \times [sum(j) - sum(p)] \, | \, (i + k - 2 \le p < j)\}\]

要注意的地方

  • 区间类型有关动态规划的问题一般可以用区间DP合并来解决
  • 注意枚举的中间点的\(p\)的范围,只有大于\(i + k - 2\)这样\(dp(i)(p)(k - 1)\)才能保证从\(m-1\)个区间转移而来

    代码

#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;
}

猜你喜欢

转载自www.cnblogs.com/lixiao189/p/9877797.html