[Codeforces1421E]Swedish Heroes

CF1421E

题意:给定长度为 (n) 的序列 (a_n),进行 (n-1) 次操作,每次选择相邻的两个数合并,合并规则是相加并取反,最大化剩下的那个数。

SakuraiMomoka的提交 完美地揭示了此题的解题过程。

首先容易发现最后答案是 (sum_{i = 1}^nsig_i imes a_i,sig_iin{0, 1}),即给每个 (a_i) 前面加上符号。

但并不是所有情况都是合法的,因此先把小数据的所有合法分配符号的方案打表出来,下面的数据来自SakuraiMomoka的提交

//~ 2
//~ --
//~ 3
//~ ++-
//~ -++
//~ 4
//~ ++++
//~ +---
//~ -+--
//~ --+-
//~ ---+
//~ 5
//~ +++--
//~ ++-+-
//~ ++--+
//~ +-++-
//~ +--++
//~ -+++-
//~ -++-+
//~ -+-++
//~ --+++
//~ -----
//~ 6
//~ +++++-
//~ ++++-+
//~ +++-++
//~ ++-+++
//~ ++----
//~ +-++++
//~ +-+---
//~ +--+--
//~ +---+-
//~ +----+
//~ -+++++
//~ -++---
//~ -+-+--
//~ -+--+-
//~ -+---+
//~ --++--
//~ --+-+-
//~ --+--+
//~ ---++-
//~ ---+-+
//~ ----++
//~ 7
//~ +++++++
//~ ++++---
//~ +++-+--
//~ +++--+-
//~ +++---+
//~ ++-++--
//~ ++-+-+-
//~ ++-+--+
//~ ++--++-
//~ ++--+-+
//~ ++---++
//~ +-+++--
//~ +-++-+-
//~ +-++--+
//~ +-+-++-
//~ +-+--++
//~ +--+++-
//~ +--++-+
//~ +--+-++
//~ +---+++
//~ +------
//~ -++++--
//~ -+++-+-
//~ -+++--+
//~ -++-++-
//~ -++-+-+
//~ -++--++
//~ -+-+++-
//~ -+-++-+
//~ -+-+-++
//~ -+--+++
//~ -+-----
//~ --++++-
//~ --+++-+
//~ --++-++
//~ --+-+++
//~ --+----
//~ ---++++
//~ ---+---
//~ ----+--
//~ -----+-
//~ ------+
 
 
//~ ------
//~ 2
//~ 0 1
//~ ------
//~ 3
//~ 2 2
//~ ------
//~ 4
//~ 1 4
//~ 4 1
//~ ------
//~ 5
//~ 0 1
//~ 3 9
//~ ------
//~ 6
//~ 2 15
//~ 5 6
//~ ------
//~ 7
//~ 1 7
//~ 4 34
//~ 7 1
//~ ------
//~ 8
//~ 0 1
//~ 3 56
//~ 6 28
//~ ------
//~ 9
//~ 2 36
//~ 5 125
//~ 8 9
//~ ------
//~ 10
//~ 1 10
//~ 4 210
//~ 7 120
//~ 10 1

发现如下结论:

  1. + 的个数以3为step迭代,即,+ 的个数 (cnt_+equiv 2 - n pmod 3);

  2. (n) 为偶数时,任意一种 + 的个数符合条件的方案都是合法的;

  3. (n)为奇数时,+ 的个数符合条件的方案只有一种不合法,即 +-+-+-+

因此容易想到一种贪心的做法:将 (a) 从大到小排序,大的选 +,小的选 - 并特判上述不合法的情况。

也可以用dp求解,这样不需要排序: (dp[i][j][0/1]) 表示前 (i) 个数,+ 的个数 (cnt_+equiv j pmod 3),是否形如 +-+-+-

关于结论1,可以使用类似归纳法的东西证明:

  1. (n = 1, 2, 3) 时成立;
  2. (cnt_n = (i - cnt_i) + (n - i - cnt_{n - i}) = n - cnt_i - cnt_{n - i} equiv 2n - 4 equiv 2 - n pmod 3) 可知结论成立。

关于结论 任意一种 + 的个数符合条件的方案都是合法的 的证明,方法类似,具体见官方题解

#include <bits/stdc++.h>
#ifdef LOCAL
#define dbg(args...) std::cerr << "33[32;1m" << #args << " -> ", err(args)
#else
#define dbg(...)
#endif
inline void err() { std::cerr << "33[0m
"; }
template<class T, class... U>
inline void err(const T &x, const U &... a) { std::cerr << x << ' '; err(a...); }
template <class T>
inline void readInt(T &w) {
  char c, p = 0;
  while (!isdigit(c = getchar())) p = c == '-';
  for (w = c & 15; isdigit(c = getchar());) w = w * 10 + (c & 15);
  if (p) w = -w;
}
template <class T, class... U>
inline void readInt(T &w, U &... a) { readInt(w), readInt(a...); }
template <class T, class U>
inline bool smin(T &x, const U &y) { return y < x ? x = y, 1 : 0; }
template <class T, class U>
inline bool smax(T &x, const U &y) { return x < y ? x = y, 1 : 0; }

typedef long long LL;
typedef std::pair<int, int> PII;

constexpr int N(2e5 + 5);
int n, a[N];
LL dp[N][3][2];
int main() {
  readInt(n);
  for (int i = 1; i <= n; i++) readInt(a[i]);
  if (n == 1) return std::cout << a[1], 0;
  memset(dp, 0xcf, sizeof dp);
  dp[0][0][1] = 0;
  for (int i = 1; i <= n; i++) {
    for (int j = 0; j < 3; j++) {
      smax(dp[i][j][0], dp[i - 1][(j + 2) % 3][0] + a[i]);
      smax(dp[i][j][0], dp[i - 1][j][0] - a[i]);
      smax(dp[i][j][i & 1], dp[i - 1][(j + 2) % 3][1] + a[i]);
      smax(dp[i][j][i & 1 ^1], dp[i - 1][j][1] - a[i]);
    }
  }
  std::cout << dp[n][((5 - n % 3) % 3)][0];
  return 0;
}
原文地址:https://www.cnblogs.com/HolyK/p/13971947.html