Aquarius's Trial H - 8 HDU - 1156 Brownie Points II

                                                             

                                                     Brownie Points II

Problem Description

Stan and Ollie play the game of Odd Brownie Points. Some brownie points are located in the plane, at integer coordinates. Stan plays first and places a vertical line in the plane. The line must go through a brownie point and may cross many (with the same x-coordinate). Then Ollie places a horizontal line that must cross a brownie point already crossed by the vertical line.
Those lines divide the plane into four quadrants. The quadrant containing points with arbitrarily large positive coordinates is the top-right quadrant.

The players score according to the number of brownie points in the quadrants. If a brownie point is crossed by a line, it doesn't count. Stan gets a point for each (uncrossed) brownie point in the top-right and bottom-left quadrants. Ollie gets a point for each (uncrossed) brownie point in the top-left and bottom-right quadrants.

Stan and Ollie each try to maximize his own score. When Stan plays, he considers the responses, and chooses a line which maximizes his smallest-possible score.

Input

Input contains a number of test cases. The data of each test case appear on a sequence of input lines. The first line of each test case contains a positive odd integer 1 < n < 200000 which is the number of brownie points. Each of the following n lines contains two integers, the horizontal (x) and vertical (y) coordinates of a brownie point. No two brownie points occupy the same place. The input ends with a line containing 0 (instead of the n of a test).

Output

For each input test, print a line of output in the format shown below. The first number is the largest score which Stan can assure for himself. The remaining numbers are the possible (high) scores of Ollie, in increasing order.

Sample Input

11 
3 2 
3 3 
3 4 
3 6 
2 -2 
1 -3 
0 0 
-3 -3 
-3 -2 
-3 -4 
3 -7 
0

Sample Output

Stan: 7; Ollie: 2 3;

Source:

https://vjudge.net/problem/17705/origin

参考文章:https://blog.csdn.net/libin56842/article/details/46582685 

这道题没怎么看懂,看别人的博客:

题意:平面上有若干点,stan通过一个点划了一条直线,ollie通过在这条垂直直线上的点作了一条水平线,平面被分成4个象限,定义stan获得的分数为1,3象限的点的数量,ollie获得的分数为2,4象限上的点的数量,线上的点不归任何人所有。两人都采用最优的策略使自己获得的点数最大。由于stan的选择具有主动权,为了对自己有利,求stan所能够获得的最小的可能的分数最大,输出该分数,并输出ollie可能的分数。

思路:首先分析可以得到:stan画的线上如果没有其他点,那么ollie的选择只有一个。如果有多个点,ollie会选择自己分数高的点,如果相同,选择stan分数低的点。

实现:

定义right[i]的,第i个正右方向,left[i],第i个负左方向,up[i],第i个正上方向,down[i]第i个负下方向,并且定义:TR,TL,BL,BR为第一象限的点。

首先对y升序排序(y相同按x升序排序),获得对large(反向),left(正向),right(反向)的统计。由于题目中没有明确的坐标范围,因此需要对点进行离散化,并且排序操作已经已经使得一个点对的一维操作已经有序,那么我们只要离散此时的y值,得到原来的下标对应的按x排序后的下标。为了得到up,down的统计值,然后再对x升序排序(x相同升序y)。如此就有我们所需要的所有数据。设定一条垂直线,水平从第一个点向右移动,得到最小的没有被访问过的点的横坐标的原来的编号对应的通过y离散化后的编号,,用树状数组维护左下的点数,计算并统计更新答案。

#include<iostream>
#include<set>
#include<algorithm>
using namespace std;
const int maxn = 200005;
int c[maxn];
int up[maxn];
int down[maxn];
int righ[maxn];
int lef[maxn];
int large[maxn];
int id[maxn];
int n;
int lowbit(int i) { return i&(-i); }
void add(int x, int v) {
	while (x<maxn) {
		c[x] += v;
		x += lowbit(x);
	}
}
int getsum(int x) {
	int res = 0;
	while (x>0) {
		res += c[x];
		x -= lowbit(x);
	}
	return res;
}
struct node {
	int x, y, id;
}p[maxn];

void init(void) {
	for (int i = 0; i <= n; i++) {
		c[i] = large[i] = up[i] = down[i] = lef[i] = righ[i] = 0;
	}
}
int cmp1(node a, node b) {
	if (a.x != b.x)return a.x<b.x;
	return a.y<b.y;
}

int cmp2(node a, node b) {
	if (a.y != b.y)return a.y<b.y;
	return a.x<b.x;
}
int main() {
	while (cin>>n&& n) {
		for (int i = 0; i < n; i++) {
			cin >> p[i].x >> p[i].y;
			p[i].id = i;
		}
		init();
		sort(p, p + n, cmp2);//先对y排序
		for (int i = 1; i < n; i++) {
			if (p[i].y == p[i - 1].y) {
				lef[p[i].id] = lef[p[i - 1].id] + 1;
			}
			if (p[n - i - 1].y == p[n - i].y) {
				large[p[n - i - 1].id] = large[p[n - i].id];
				righ[p[n - i - 1].id] = righ[p[n - i].id] + 1;
			}
			else {
				large[p[n - i - 1].id] = i;
			}
		}
		int k = 1;
		id[p[0].id] = k;
		for (int i = 1; i < n; i++) {//对y离散化
			if (p[i].y == p[i - 1].y) {
				id[p[i].id] = k;
			}
			else {
				id[p[i].id] = ++k;
			}
		}
		sort(p, p + n, cmp1);
		for (int i = 1; i < n; i++) {
			if (p[i].x == p[i - 1].x) {
				down[p[i].id] = down[p[i - 1].id] + 1;
			}
			if (p[n - i - 1].x == p[n - i].x) {
				up[p[n - i - 1].id] = up[p[n - i].id] + 1;
			}
		}
		int px = p[0].x;//垂直线
		set<int>st;
		int s_min_max = 0;
		for (int i = 0; i < n; i++) {
			int omin = maxn;
			int omax = 0;
			while (i < n&&p[i].x == px) {//竖直线上的所有的点
				int yid = id[p[i].id];//离散化后的点
				int BL = getsum(yid) - lef[p[i].id] - down[p[i].id];
				int TL = i - BL - lef[p[i].id] - down[p[i].id];
				int TR = large[p[i].id] - TL - up[p[i].id];
				int BR = n - 1 - TL - TR - BL - up[p[i].id] - lef[p[i].id] - righ[p[i].id] - down[p[i].id];
				add(yid, 1);
				int ollie = TL + BR;
				if (omax < ollie) {
					omax = ollie;
					omin = TR + BL;
				}
				else if (omax == ollie) {
					omin = min(omin, TR + BL);
				}
				i++;
			}
			if (i < n)px = p[i--].x;
			if (omin > s_min_max) {
				s_min_max = omin;
				st.clear();
				st.insert(omax);
			}
			else if (omin == s_min_max) {
				st.insert(omax);
			}
		}
		cout << "Stan: " << s_min_max << "; Ollie:";
		set<int>::iterator it;
		for (it = st.begin(); it != st.end(); it++) {
			cout <<" "<<*it;
		}
		cout << ";\n";
	}
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值