【BZOJ2369】区间

【题目链接】

【双倍经验连接】

【思路要点】

  • 我们发现选取三个及以上个数的区间是没有意义的,因为首先我们选取的所有区间需要是有交的,这便意味着所有区间的并由左端点最靠左的区间和右端点最靠右的区间直接确定,删去其余的区间不会使区间的并或区间的交减少,因此我们可以认为我们只会选取两个区间。

  • 我们选取的两个区间的关系有可能是包含或相交。

  • 考虑有包含关系的区间 A , B , C ,其中 A B , A C ,那么可以发现选取 ( B , C ) 的收益会不小于选取 ( A , C ) ( A , B ) 的收益,因此我们可以认为在考虑包含关系的时候,一个区间可以任意与一个包含它的区间配对,而所漏掉的情况会在相交关系的部分有更好的解。

  • 接下来,我们只需要考虑有相交关系两个区间,不妨认为此时区间的左端点以及右端点均单调递增。

  • 考虑选择 ( [ l 1 , r 1 ] , [ l 2 , r 2 ] ) 的收益和选择 ( [ l 1 , r 1 ] , [ l 3 , r 3 ] ) 的收益,将它们作差,有

    δ = ( r 3 l 1 ) ( r 1 l 3 ) ( r 2 l 1 ) ( r 1 l 2 ) = ( r 3 r 2 ) r 1 + ( l 3 l 2 ) l 1 + l 2 r 2 l 3 r 3

  • 我们发现对于固定区间 [ l 1 , r 1 ] 右侧的两个区间 [ l 2 , r 2 ] , [ l 3 , r 3 ] ( l 3 > l 2 , r 3 > r 2 ) ,一旦选取 ( [ l 1 , r 1 ] , [ l 3 , r 3 ] ) 优于 ( [ l 1 , r 1 ] , [ l 2 , r 2 ] ) ,那么对于 [ l 1 , r 1 ] 右侧的每个区间 [ l x , r x ] ,均有选取 ( [ l x , r x ] , [ l 3 , r 3 ] ) 优于 ( [ l x , r x ] , [ l 2 , r 2 ] ) 因此,每个区间右侧的最优决策区间具有决策单调性。

  • 分治解决即可,时间复杂度 O ( N L o g N )

【代码】


#include<bits/stdc++.h>

using namespace std;
const int MAXN = 1000005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
  x = 0; int f = 1;
  char c = getchar();
  for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
  for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
  x *= f;
}
template <typename T> void write(T x) {
  if (x < 0) x = -x, putchar('-');
  if (x > 9) write(x / 10);
  putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
  write(x);
  puts("");
}
struct info {int l, r; };
int n; info a[MAXN];
long long ans;
bool cmp(info x, info y) {
  if (x.l == y.l) return x.r > y.r;
  else return x.l < y.l;
}
void solve(int l, int r, int sl, int sr) {
  int mid = (l + r) / 2;
  long long tans = 0; int home = max(mid + 1, sl);
  for (int i = max(mid + 1, sl); i <= sr; i++) {
      long long tmp = 1ll * (a[i].r - a[mid].l) * (a[mid].r - a[i].l);
      if (tmp >= tans) {
          tans = tmp;
          home = i;
      }
  }
  chkmax(ans, tans);
  if (mid > l) solve(l, mid - 1, sl, home);
  if (mid < r) solve(mid + 1, r, home, sr);
}
int main() {
  read(n);
  for (int i = 1; i <= n; i++)
      read(a[i].l), read(a[i].r);
  sort(a + 1, a + n + 1, cmp);
  int Max = 0, tn = 0;
  for (int i = 1; i <= n; i++) {
      if (a[i].r > a[Max].r) {
          Max = ++tn;
          a[tn] = a[i];
      } else chkmax(ans, 1ll * (a[i].r - a[i].l) * (a[Max].r - a[Max].l));
  }
  solve(1, tn, 1, tn);
  writeln(ans);
  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/81001241