洛谷 P5851 [USACO19DEC]Greedy Pie Eaters P

思路

我们用 \(f_{i.j}\) 来表示 \([i,j]\) 区间内的最大的权值和。
\(p_{k.i.j}\) 表示 \(k\) 未被吃且 \(i \leq l \leq k \leq r\leq j\) 的最大的一个 \(w\)

我们发现 \(f_{i.j} = \max \{ f_{i,k-1} + f_{k+1,j} + p_{k.i.j}\}\)

那么 \(p\) 应该怎么求出呢??我也不知道
\(p_{k,i,j}\) 肯定是可以先预处理出来的,其实思路也基本就是区间 dp 的思路,

\(p_{k,i-1,j}=\max \{p_{k,i-1,j}, p_{k,i,j} \}\)

\(p_{k,i,j+1}=\max \{p_{k,i,j+1},p_{k,i,j} \}\)

也就是通过已经得出的一个个向外更新,最终扩展到整个序列。

code

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define N 100010
#define M 310

using namespace std;
const int mod = 1e9+7;
const int inf = 0x3f3f3f3f;
int n, m;
int f[M][M], p[M][M][M];

inline int read() {
  char c = getchar(); int x = 0, f = 1;
  for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
  for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
  return x * f;
}

inline void Max(int &a, int b) {
  if (a < b) a = b;
}

int main() {
  n = read(), m = read();
  for (register int i = 1, w, l, r; i <= m; i++) {
    w = read(), l = read(), r = read();
    for (register int j = l; j <= r; j++) p[j][l][r] = w;
  }
  for (register int k = 1; k <= n; k++)
    for (register int i = k; i >= 1; i--)
      for (register int j = k; j <= n; j++) {
        if (i != 1) Max(p[k][i - 1][j], p[k][i][j]);
        if (j != n) Max(p[k][i][j + 1], p[k][i][j]);
      }
  for (register int i = n; i >= 1; i--)
    for (register int j = 1; j <= n; j++) {
      for (register int k = i; k <= j; k++)
        Max(f[i][j], f[i][k] + f[k + 1][j]);
      for (register int k = i; k <= j; k++)
        Max(f[i][j], f[i][k - 1] + f[k + 1][j] + p[k][i][j]);
    }
  printf("%d\n", f[1][n]);
}
posted @ 2020-10-27 20:10  Kersen  阅读(109)  评论(0)    收藏  举报