矩形计数
来源:互联网 发布:苹果广告屏蔽软件 编辑:程序博客网 时间:2024/05/18 06:21
题目大意:在一个以(0,0)为左下角,(w,h)为右上角的矩形内,有n个标记。统计有多少个小矩形,满足端点都在大矩形内的整点上,且平行于x轴和y轴,且这些矩形不包含任何一个被标记的点(包括边界上和端点)。这些矩形可以是退化的矩形(即面积为0)。答案mod 1 000 000 007。w,h <= 10^9,n <= 2000。
首先将所有的点进行离散化,那么对于每一个枚举出来的矩形(图中加粗矩形),如图,统计出有多少个小矩形的右上角在该矩形内。
为了避免重复,该矩形的范围是[x0, x1), [y0, y1)。我们的统计分成4个部分。
1.小矩形在该矩形内,这个可以用等差数列一类的东东算出来(要知道,该矩形内是没有标记点的。为什么,因为我们是离散化的);
2.小矩形左边的那一条边在该矩形左边(就是图中加粗矩形左边的灰色矩形), 右边的一条边在该矩形内。
3.小矩形下面的那一条边在该矩形下面(图中加粗矩形下面的灰侧矩形),上面的一条边也在该矩形内。
4.小矩形的左下角在合法区域内,右上角在该矩形内。所谓的合法区域,比如图中的橙色点,只要在橙色矩形内没有标记,那就是合法的点,所以橙色点是合法的,蓝色点是不合法的。这个合法点的个数统计,用一个栈来维护,因为这些点构成的形状类似楼梯的样子(图中有)。
统计的时候,用扫描线对x进行扫描,对于每一个x,再用一条扫描线对y进行扫描,这时候就用栈把信息传上去。
详细看代码:
#include <cstdio>#include <iostream>using namespace std;typedef long long ll;//....这个读入会快些,但这题没什么必要 inline int Scan() { int res = 0; char ch; do { ch = getchar(); }while (ch < '0' || ch > '9'); while (ch >= '0' && ch <= '9') { res = res * 10 + (int) ch - '0'; ch = getchar(); } return res;}#define maxn 2013int n;ll w, h;#define x first#define y second// 坐标 typedef pair<ll, ll> Data;// 标记的坐标, 分别按x,y排序,(指针类型) Data dat[maxn], *rx[maxn], *ry[maxn];//按x从小到大排序 inline bool cmpx(Data *i, Data *j) { return i -> x < j -> x || (i -> x == j -> x && i -> y < j -> y);}//按y从小到大排序 inline bool cmpy(Data *i, Data *j) { return i -> y < j -> y || (i -> y == j -> y && i -> x < j -> x);}void Init() { w = (ll) Scan(), h = (ll) Scan(), n = Scan(); for (int i = 0; i < n; i ++) { dat[i].x = (ll) Scan(), dat[i].y = (ll) Scan(); rx[i] = ry[i] = &dat[i]; } dat[n].x = -1, dat[n].y = -1; rx[n] = ry[n ++] = &dat[n]; //为了处理方便,多加个点 sort(rx, rx + n, cmpx); sort(ry, ry + n, cmpy);}// 栈 Data *list[maxn];// 统计点数 ll area[maxn];const ll mod = 1000000007;// 1 + 2 + 3 + ... + a 的和 inline ll C(ll a) { return (((1 + a) * a) >> 1) % mod;}inline ll add(ll a, ll b) { return (a + b) % mod;}inline ll mul(ll a, ll b) { return (a * b) % mod;}void Solve() { ll res = 0LL; //再多加个点, 方便统计 rx[n] = ry[n] = &dat[n]; dat[n].x = w + 1, dat[n].y = h + 1; //初始化栈底 list[0] = new Data; list[0] -> x = list[0] -> y = -1; area[0] = 0; for (int i = 0; i < n; i ++) // 对于x的扫描线 if (rx[i] -> x != rx[i+1] -> x) { int x0 = rx[i] -> x, x1 = rx[i+1] -> x; int j = 0, top = 0; for (; j < n; j ++) { // 对于y的扫描线 if (ry[j] -> x > x0) continue; // 若纵坐标相等,则取横坐标最大的 while (ry[j] -> y == ry[j+1] -> y && ry[j+1] -> x <= x0) j ++; // 找出下一条扫描线 int p = j + 1; while (p < n && (ry[j] -> y == ry[p] -> y || ry[p] -> x > x0)) p ++; int y0 = ry[j] -> y, y1; if (p == n) y1 = h + 1; else y1 = ry[p] -> y; //统计1 res = add(res, mul(C(x1 - x0 - 1), C(y1 - y0 - 1))); //统计2 res = add(res, mul(mul(x0 + 1, C(y1 - y0 - 1)), x1 - x0)); //统计3 res = add(res, mul(mul(y0 + 1, C(x1 - x0 - 1)), y1 - y0)); //把不合法的弹出 while (top > 0 && list[top] -> x < ry[j] -> x) top --; //加入当前的点 list[++ top] = ry[j]; area[top] = add(area[top-1], mul(y0 - list[top-1] -> y, x0 - list[top] -> x)); //统计4 res = add(res, mul(area[top], mul(x1 - x0, y1 - y0))); } } cout << res << endl;}int main() { freopen("rectangles.in", "r", stdin); freopen("rectangles.out", "w", stdout); Init(); Solve(); return 0;}
- 矩形计数
- #1476 : 矩形计数
- hihocoder #1476 : 矩形计数
- RQNOJ 698(矩形计数-圆内接矩形数)
- hihoCoder 1476 矩形计数 dp
- POJ 2029 矩形计数 简单 DP
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- 矩形
- MC新手入门(三十八)------ 绘制函数
- Object-C常用第三方库
- 数据结构_查找_次优查找树
- C++之父元旦专访(8+13个问题,关于C++的学习&使用和未来)
- 关于Spring中dataSource的配置
- 矩形计数
- 往query插入多个参数的方法
- 为什么C++(中文版——感谢waterwalk翻译)
- mysql中pager命令的妙用
- ORACLE 11g新特性 DRA(Data Recovery Adviseor)
- APDU命令
- C++ 指针 (2)-指针入门
- PHP排雷之编码问题
- MC新手入门(三十九)------ 声音函数、游戏控制器