Forever Young

洛谷 P2123 皇后游戏

思路

感谢 liuzibujian 的思路

错误做法

感觉和国王游戏很像,所以像国王游戏一样,试着用相邻比较法试一下可不可以做。
设现在要比较的两个大臣为 \(i, j\)\(j\)\(i\) 后,\(i\) 前面所有大臣左手的值的和为 \(x\)\(i\) 的前一个大臣的奖金数为 \(y\),如果不交换,那么到目前最大的奖金数 \(c_j\) 就是

\[\max(\max(x+a_i+ b_i, y+b_i), x+a_i+a_j)+b_j \]

化简得

\[\max(x+a_i+b_i+b_j,y+b_i+b_j,x+a_i+a_j+b_j) \]

同理,若交换,则得到的最大值为

\[\max(x+a_j+b_j+b_i,y+b_j+b_i,x+a_j+a_i+b_i) \]

假设不交换更优,那么有

\[\max(x+a_i+b_i+b_j,y+b_i+b_j,x+a_i+a_j+b_j)\le\max(x+a_j+b_j+b_i,y+b_j+b_i,x+a_j+a_i+b_i) \]

\(y+b_i+b_j\) 消去得到

\[\max(x+a_i+b_i+b_j,x+a_i+a_j+b_j)\le\max(x+a_j+b_j+b_i,x+a_j+a_i+b_i) \]

现在就可以消去 \(x\),得到

\[\max(a_i+b_i+b_j,a_i+a_j+b_j)\le\max(a_j+b_j+b_i,a_j+a_i+b_i) \]

化简得

\[\max(b_i,a_j)+a_i+b_j\le \max(b_j,a_i)+a_j+b_i \]

移项得

\[\max(b_i,a_j)-a_j-b_i\le \max(b_j,a_i)-a_i-b_j \]

可以看出,两边较大的值都被消掉了,得到的就是

\[-\min(a_j,b_i)\le - \min(b_j,a_i) \]

进而得到

\[\min(b_j,a_i)\le\min(a_j,b_i) \]

一个简单的式子,也就是排序所用的式子。

正确做法

其实上面的式子是不满足传递性的,所以要找一个满足传递性的式子,正确做法应该是:

  1. \(a_i<b_i,a_j<b_j\) 时,\(a_i\le a_j\),按 \(a\) 升序排序
  2. \(a_i=b_i,a_j=b_j\) 时,随便排
  3. \(a_i>b_i,a_j>b_j\) 时,\(b_i\ge b_j\),按 \(b\) 降序排序

要保证 \(1\)\(2\) 前,\(2\)\(3\) 前,

\(d_i=\dfrac{a_i-b_i}{|a_i-b_i|}\),第一组的 \(d\)\(-1\),第二组为 \(0\),第三组为 \(1\)

\(d\) 排序,如果 \(d\le 0\),按 \(a\) 升序排序,否则按 \(b\) 排序。

代码

错误做法

/*
  Name: P2123 皇后游戏
  Author: Loceaner
  Date: 01/09/20 19:13
  Description: 贪心 
  Debug:
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long 
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

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

int n, c[A], sum[A];
struct node { int a, b; } w[A];

bool cmp(node x, node y) {
  return min(y.b, x.a) < min(y.a, x.b);
}

inline void solve() {
  n = read();
  for (int i = 1; i <= n; i++) 
    w[i].a = read(), w[i].b = read();
  sort(w + 1, w + 1 + n, cmp);
  for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + w[i].a;
  for (int i = 1; i <= n; i++) 
    c[i] = max(c[i - 1], sum[i]) + w[i].b;
  cout << c[n] << '\n';
  return;
}

signed main() {
  int T = read();
  while (T--) solve();
}

正确做法

/*
  Name: P2123 皇后游戏
  Author: Loceaner
  Date: 01/09/20 19:13
  Description: 贪心 
  Debug:
*/
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define int long long 
using namespace std;

const int A = 1e5 + 11;
const int B = 1e6 + 11;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;

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

int n, c[A], sum[A];
struct node { int a, b, d; } w[A];

bool cmp(node x, node y) {
  return x.d != y.d ? x.d < y.d : (x.d <= 0 ? x.a < y.a : x.b > y.b);
}

inline void solve() {
  n = read();
  for (int i = 1; i <= n; i++) {
    int a = read(), b = read();
    w[i].a = a, w[i].b = b;
    w[i].d = (w[i].a - w[i].b > 0) ? 1 : -1;
  }
  sort(w + 1, w + 1 + n, cmp);
  for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + w[i].a;
  for (int i = 1; i <= n; i++) 
    c[i] = max(c[i - 1], sum[i]) + w[i].b;
  cout << c[n] << '\n';
  return;
}

signed main() {
  int T = read();
  while (T--) solve();
}
posted @ 2020-09-01 21:57  Loceaner  阅读(188)  评论(0编辑  收藏  举报