CF1194E Count The Rectangles

CF1194E Count The Rectangles

在坐标系上给定一些平行于 \(x\) 轴 或 \(y\) 轴 的线段,求一共能围成多少个不同的矩形

\(n\leq5000, |x|,\ |y|\in[0,\ 5000]\)

乱搞,bitset


这是一篇 非正解

\(n1=\) 平行于 \(y\) 轴的线段数, \(n2=\) 平行于 \(x\) 轴的线段数

考虑任意两条平行于 \(y\) 轴的线段对答案的贡献,令 \(s=\) 同时与两条线段相交的平行于 \(x\) 轴的线段数,贡献即为 \(\frac{s(s-1)}{2}\)

可以考虑枚举每两条平行于 \(y\) 轴的线段,统计答案可以考虑对于每条平行于 \(y\) 轴的线段,预处理与之相交的平行于 \(x\) 轴的线段并用 bitset 存储,之后暴力 bitset 操作

时间复杂度 \(O(\frac{n^3}{w})\) ,仍然跑不过

可以发现这个做法的时间复杂度瓶颈在于每次 bitset 操作的时间复杂度都是 \(\frac{5000}{w}\) 的,而我们只需要统计 bitset 前 \(n2\) 位,可以考虑 手写 bitset

考虑这样做的最坏时间复杂度,把 \(n1\) 取到 \(3333\) ,大概会跑 \(3333^2\times(5000-3333)/64/2\approx1.4\times10^8\),cf机子两秒完全不虚

时间复杂度 \(O(\frac{n^3}{w})\)

代码

#include <bits/stdc++.h>
using namespace std;

const int maxn = 5010;
int n, n1, n2, tot;

struct node1 {
  int x, y1, y2;
} a[maxn];

struct node2 {
  int x1, x2, y;
} b[maxn];

typedef unsigned long long u64;

struct Bitset {
  u64 s[maxn >> 6];

  inline void set(int x) {
    s[x >> 6] |= 1llu << (x & 63);
  }
} tmp, f[maxn];

inline int add(int x, int y) {
  int ans = 0;
  for (register int i = 0; i <= tot; ++i) {
    ans += __builtin_popcountll(f[x].s[i] & f[y].s[i]);
  }
  return ans;
}

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; ++i) {
    int x1, x2, y1, y2;
    scanf("%d %d %d %d", &x1, &y1, &x2, &y2);
    if (x1 == x2) {
      if (y1 > y2) swap(y1, y2);
      a[++n1] = node1{x1, y1, y2};
    } else {
      if (x1 > x2) swap(x1, x2);
      b[++n2] = node2{x1, x2, y1};
    }
  }
  tot = n2 >> 6;
  for (int i = 1; i <= n1; ++i) {
    for (int j = 1; j <= n2; ++j) {
      if (b[j].x1 <= a[i].x && a[i].x <= b[j].x2 && a[i].y1 <= b[j].y && b[j].y <= a[i].y2) {
        f[i].set(j);
      }
    }
  }
  long long ans = 0;
  for (int i = 1; i < n1; ++i) {
    for (int j = i + 1; j <= n1; ++j) {
      int s = add(i, j);
      ans += s * (s - 1);
    }
  }
  printf("%I64d", ans >> 1);
  return 0;
}
posted @ 2019-07-15 15:22  cnJuanzhang  阅读(452)  评论(1编辑  收藏  举报