洛谷P1880题解

题目
第一类区间DP模板题。
所谓第一类区间DP,是指合并型区间DP,状态转移方程一般形如 \(f_{i,j}=\max{f_{i,k}+f_{k+1,j}+cost_{i,j}}\) ,时间复杂度一般是 \(O(n^3)\)
这道题因为在环上,不能直接套板子,我们考虑:

  1. 断环成链,时间复杂度 \(O(n^4)\) 。如果加火车头之类的东西的话勉强能卡过去。
  2. 倍长原环,做完DP以后在长度为 \(n\)\(n\) 个区间内找最优解。时间复杂度 \(O(n^3)\),可以通过本题。

就本题而言,状态转移方程可以套用板子。\(f_{i,j}=\max{f_{i,k}+f_{k+1,j}+\begin{matrix} \sum_{m=i}^j a[m] \end{matrix}}\)
代码:

#include<stdio.h>
#define reg register
#define ri reg int
#define rep(i, x, y) for(ri i = x; i <= y; ++i)
#define nrep(i, x, y) for(ri i = x; i >= y; --i)
#define DEBUG 1
#define ll long long
#define il inline
#define swap(a, b) ((a) ^= (b) ^= (a) ^= (b))
#define max(i, j) (i) > (j) ? (i) : (j)
#define min(i, j) (i) < (j) ? (i) : (j)
#define read(i) io.READ(i)
#define print(i) io.WRITE(i)
#define push(i) io.PUSH(i)
struct IO {
#define MAXSIZE (1 << 20)
#define isdigit(x) (x >= '0' && x <= '9')
  char buf[MAXSIZE], *p1, *p2;
  char pbuf[MAXSIZE], *pp;
#if DEBUG
#else
  IO() : p1(buf), p2(buf), pp(pbuf) {}
  ~IO() {
    fwrite(pbuf, 1, pp - pbuf, stdout);
  }
#endif
  inline char gc() {
#if DEBUG
    return getchar();
#endif
    if(p1 == p2)
      p2 = (p1 = buf) + fread(buf, 1, MAXSIZE, stdin);
    return p1 == p2 ? ' ' : *p1++;
  }
  inline bool blank(char ch) {
    return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t';
  }
  template <class T>
  inline void READ(T &x) {
    register double tmp = 1;
    register bool sign = 0;
    x = 0;
    register char ch = gc();
    for(; !isdigit(ch); ch = gc())
      if(ch == '-') sign = 1;
    for(; isdigit(ch); ch = gc())
      x = x * 10 + (ch - '0');
    if(ch == '.')
      for(ch = gc(); isdigit(ch); ch = gc())
        tmp /= 10.0, x += tmp * (ch - '0');
    if(sign) x = -x;
  }
  inline void READ(char *s) {
    register char ch = gc();
    for(; blank(ch); ch = gc());
    for(; !blank(ch); ch = gc())
      *s++ = ch;
    *s = 0;
  }
  inline void READ(char &c) {
    for(c = gc(); blank(c); c = gc());
  }
  inline void PUSH(const char &c) {
#if DEBUG
    putchar(c);
#else
    if(pp - pbuf == MAXSIZE) {
      fwrite(pbuf, 1, MAXSIZE, stdout);
      pp = pbuf;
    }
    *pp++ = c;
#endif
  }
  template <class T>
  inline void WRITE(T x) {
    if(x < 0) {
      x = -x;
      PUSH('-');
    }
    static T sta[35];
    T top = 0;
    do {
      sta[top++] = x % 10;
      x /= 10;
    } while(x);
    while(top)
      PUSH(sta[--top] + '0');
  }
  template <class T>
  inline void WRITE(T x, char lastChar) {
    WRITE(x);
    PUSH(lastChar);
  }
} io;
int n, a[210], sum[210];
int f1[210][210], f2[210][210];
int main() {
  ll ans = 1ll << 50;
  read(n);
  rep(i, 1, n) read(a[i]), a[i + n] = a[i];
  rep(i, 1, n + n) sum[i] = sum[i - 1] + a[i];
  rep(i, 1, 2 * n) rep(j, 1, 2 * n) {
    if(i == j) f1[i][j] = 0;
    else f1[i][j] = 1 << 29;
    f2[i][j] = 0;
  }
  rep(len, 1, n) {
    rep(i, 1, n * 2 - len - 1) {
      ri j = i + len - 1;
      rep(k, i, j - 1) {
        f1[i][j] = min(f1[i][j], f1[i][k] + f1[k + 1][j] + sum[j] - sum[i - 1]);
        f2[i][j] = max(f2[i][j], f2[i][k] + f2[k + 1][j] + sum[j] - sum[i - 1]);
      }
    }
  }
  rep(i, 1, n) ans = min(ans, f1[i][i + n - 1]);
  print(ans);
  puts("");
  ans = 0;
  rep(i, 1, n) ans = max(ans, f2[i][i + n - 1]);
  print(ans);
}

注意初始化都要开到 \(2\times n\)

posted @ 2021-03-27 08:18  1358id  阅读(86)  评论(0编辑  收藏  举报