• [OJ#39]左手右手


    [OJ#39]左手右手

    试题描述

    有 n 个人,每个人左右手上各写着一个整数。对于编号为 a 的人和编号为 b 的人, a 对 b 的好感度等于 a 左手上写的数字乘 b 右手上写的数字,a 和 b 的好感度差异等于 a 对 b 的好感度与 b 对 a 的好感度之差的绝对值。

    现在,你要从这 n 个人中找出两个人使得他们的好感度差异最大。

    输入

    第一行一个整数 n

    接下来 n 行,每行两个整数 ai,bi,分别表示第 i 个人左右手上写的数字。

    输出

    输出一个整数表示好感度差异的最大值。

    输入示例

    5
    9 -1
    7 8
    -2 4
    9 -6
    3 5

    输出示例

    114

    数据规模及约定

    2n105109ai,bi109

    题解

    首先我们可以发现两个人 i, j 的好感度差异就是两个向量 (ai, bi) 和 (aj, bj) 的叉积的绝对值。那么要让这个值最大,就是要选择两个向量使得它们围成的三角形面积最大。

    我们不妨先枚举其中一个向量 x,可以发现与它叉积绝对值最大的向量 y 一定在凸包上。我们做平行于向量 x 的直线,显然如果向量 y 的终点在直线上,这条直线离原点越远越好,所以一定是在凸包上的。

    所以我们先处理出凸包,然后把所有向量按照极角排序,用旋转卡壳的方法去做就可以 O(n) 了。

    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <cctype>
    #include <algorithm>
    #include <cmath>
    using namespace std;
    
    int read() {
    	int x = 0, f = 1; char c = getchar();
    	while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    	while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    	return x * f;
    }
    
    #define maxn 100010
    #define LL long long
    
    struct Vec {
    	LL x, y;
    	Vec() {}
    	Vec(LL _, LL __): x(_), y(__) {}
    	
    	Vec operator - (const Vec& t) const { return Vec(x - t.x, y - t.y); }
    	LL operator ^ (const Vec& t) const { return x * t.y - y * t.x; }
    	
    	bool operator < (const Vec& t) const { return x != t.x ? x < t.x : y < t.y; }
    } ps[maxn], poly[maxn];
    int cntp, S[maxn], top;
    
    bool cmp(Vec a, Vec b) {
    	return atan2((double)a.y, (double)a.x) > atan2((double)b.y, (double)b.x);
    }
    
    #define nxt(x) (x + 1) % cntp
    #define pre(x) (x + cntp - 1) % cntp
    
    int main() {
    	int n = read();
    	for(int i = 1; i <= n; i++) {
    		int a = read(), b = read();
    		ps[i] = Vec(a, b);
    	}
    	
    	sort(ps + 1, ps + n + 1);
    	S[top = 1] = 1;
    	for(int i = 2; i <= n; i++) {
    		while(top > 1 && (ps[S[top]] - ps[S[top-1]] ^ ps[i] - ps[S[top]]) >= 0) top--;
    		S[++top] = i;
    	}
    	for(int i = 1; i <= top; i++) poly[cntp++] = ps[S[i]];
    	int upend = cntp - 1;
    	S[top = 1] = 1;
    	for(int i = 2; i <= n; i++) {
    		while(top > 1 && (ps[S[top]] - ps[S[top-1]] ^ ps[i] - ps[S[top]]) <= 0) top--;
    		S[++top] = i;
    	}
    	for(int i = top - 1; i > 1; i--) poly[cntp++] = ps[S[i]];
    	
    	sort(ps + 1, ps + n + 1, cmp);
    	int l = 0, r = upend; LL ans = 0;
    	for(int i = 1; i <= n; i++) {
    		while(!((ps[i] ^ poly[nxt(l)] - poly[l]) > 0 ^ (ps[i] ^ poly[l] - poly[pre(l)]) > 0)) l = nxt(l);
    		while(!((ps[i] ^ poly[nxt(r)] - poly[r]) > 0 ^ (ps[i] ^ poly[r] - poly[pre(r)]) > 0)) r = nxt(r);
    		ans = max(ans, max(abs(ps[i] ^ poly[l]), abs(ps[i] ^ poly[r])));
    	}
    	printf("%lld
    ", ans);
    	
    	return 0;
    }
    
  • 相关阅读:
    Java多线程同步和异步问题
    最优二叉查找树
    岛屿的周长
    Mac 环境下 go 国内代理配置
    岛屿数量
    字符串解码
    环形链表 II
    颜色分类
    无重复字符的最长子串
    完全平方数
  • 原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/6605632.html
Copyright © 2020-2023  润新知