2019 HL暑假集训 Day 3

题目按难度从简到难手动排序————题记

T1:三笔画(3lines)

【题目描述】:

二维平面内有 n 个不同的点, Alice 需要在平面内画至多 3 条直线使得所有点在直线上。
问: Alice 能否完成任务, 如果能, 输出”YES”; 否则, 输出”NO”。
注意: 由于 Alice 的画图水平有限, 直线只能平行于坐标轴。

【输入数据】:

第一行,一个整数 n。
接下来 n 行,第 i+1 行包含空格隔开的整数 xi,yi,表示第 i 个点的坐标。

【输出数据】:

若 Alice 能完成任务, 输出”YES”, 否则输出”NO”。

【样例输入】:

6
1 7
0 0
1 2
2 0
1 4
3 4

【样例输出】:

YES

【样例解释】:

三条直线分别为 x=1,y=0,y=4。

【数据范围】:

对于 30%的数据,1 <= n <= 13。
对于 60%的数据,1 <= n <= 20。
对于 100%的数据,1 <= n <= 5e4,0 <= xi, yi <= 1e9。


心路历程:对于这道题,在考场上我思考了很久,经过分析,我发现如果在一条线上有超过3个点,说明必须要使用一条线去覆盖这几个点,就使 L i n e − 1 Line-1 Line1 L i n e Line Line初始值为3),将这几个点删去。如果没有这种情况,那么就暴力枚举剩余Line条线,判断是否可以覆盖。对于大数据,这种方法很有效,对于小数据,那就直接暴力吧!【φ(>ω<*)】
正解:对于三条直线的状态,只有以下2种状态:

  • 1. 1. 1.三条水平线
  • 2. 2. 2.两条水平线+一条垂直线
    (剩余情况旋转坐标轴即可)
    我们用一个数组统计同一 y y y 坐标上有几个点。
    对于 ① 的情况,只需判断是否只有三个及以下的 y y y 坐标上有点即可。
    对于 ② 的情况,可以枚举垂直线的 x 坐标,将这条垂直线上的点全部删去,判断剩下的点的 y y y 坐标是否只有两种及以下。
    因为 x i , y i xi,yi xi,yi有些大,可以先进行离散化预处理后再进行操作。
    将点按 x x x 坐标排序后即可做到 O ( n ) O(n) O(n)的扫描.
非正解代码如下:
#include <bits/stdc++.h>

using namespace std;
const int N = 600000;

int n;
int x[N], y[N];

bool check(int p1,int t1,int p2,int t2,int p3,int t3)
{
   
	int ans = 0;
	for (int i=1;i<=n;++i) {
   
		if (x[i] == p1 && t1 == 1) ans ++;
		else if (x[i] == p2 && t2 == 1) ans ++;
		else if (x[i] == p3 && t3 == 1) ans ++;
		else if (y[i] == p1 && t1 == 2) ans ++;
		else if (y[i] == p2 && t2 == 2) ans ++;
		else if (y[i] == p3 && t3 == 2) ans ++; 
	}
	return ans == n;
}

bool work1(void)
{
   
	for (int i=1;i<=n;++i)
		for (int j=1;j<=n;++j)
			for (int k=1;k<=n;++k) {
   
				if (check(x[i],1,x[j],1,x[k],1)) return 1;
				if (check(x[i],1,x[j],1,y[k],2)) return 1;
				if (check(x[i],1,y[j],2,x[k],1)) return 1;
				if (check(x[i],1,y[j],2,y[k],2)) return 1;
				if (check(y[i],2,x[j],1,x[k],1)) return 1;
				if (check(y[i],2,x[j],1,y[k],2)) return 1;
				if (check(y[i],2,y[j],2,x[k],1)) return 1;
				if (check(y[i],2,y[j],2,y[k],2)) return 1;
			}
	return 0;
}

bool work2(void)
{
   
	map <int,int> cnt1;
	map <int,int> cnt2;
	map <int,int> cnt3;
	map <int,int> cnt4;	
	int cnt_x = 0, cnt_y = 0, P = -1, T = -1;
	for (int i=1;i<=n;++i) 
		cnt1[x[i]] ++, cnt2[y[i]] ++;
	for (int i=1;i<=n;++i) 
	{
   
		if (cnt1[x[i]] > 3) {
   
			P = x[i], T = 1;
			break;
		}
		if (cnt2[y[i]] > 3) {
   
			P = y[i], T = 2
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值