首页 > 其他分享 >AtCoder Beginner Contest 220 G Isosceles Trapezium

AtCoder Beginner Contest 220 G Isosceles Trapezium

时间:2023-06-15 21:57:01浏览次数:43  
标签:AtCoder vc frac Beginner Trapezium int scd return const

洛谷传送门

AtCoder 传送门

简单题。

首先肯定是要枚举梯形其中一条底边的两个端点的。那么另一条底边除了斜率与这条边相等,两个端点的距离要分别与这条底边两个端点的距离相等。

发现这个十分不好做,考虑一个梯形是等腰梯形的一个充要条件。不难想到,连接两底中点,这条线段垂直于两条底边。于是除了要满足斜率相等外,还要满足两个点的中点连线的斜率为底边斜率的负倒数。要限定 \(\frac{y_1 - y_2}{x_1 - x_2} = k\),移项得到 \(y_1 - k x_1 = y_2 - k x_2\)。于是只需限定这一项相等即可。实现时可以用 map。

注意一些细节,为了避免精度问题可以自己手写分数类,而且要特殊处理底边为水平线或竖直线的情况,两底还不能共线(可以把重合的直线放一起处理)。

时间复杂度 \(O(n^2 \log n)\),常数有点大。

code
// Problem: G - Isosceles Trapezium
// Contest: AtCoder - AtCoder Beginner Contest 220
// URL: https://atcoder.jp/contests/abc220/tasks/abc220_g
// Memory Limit: 1024 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 1010;

struct frac {
	ll x, y;
	frac(ll a = 0, ll b = 1) {
		if (b < 0) {
			a = -a;
			b = -b;
		}
		x = a;
		y = b;
	}
};

inline bool operator < (const frac &a, const frac &b) {
	return a.x * b.y < a.y * b.x;
}

inline bool operator == (const frac &a, const frac &b) {
	return a.x * b.y == a.y * b.x;
}

inline frac operator + (const frac &a, const frac &b) {
	return frac(a.x * b.y + a.y * b.x, a.y * b.y);
}

inline frac operator - (const frac &a, const frac &b) {
	return frac(a.x * b.y - a.y * b.x, a.y * b.y);
}

inline frac operator * (const frac &a, const frac &b) {
	return frac(a.x * b.x, a.y * b.y);
}

ll n;
struct node {
	ll x, y, z;
} a[maxn];

inline frac getb(int i, int j) {
	frac k(a[i].y - a[j].y, a[i].x - a[j].x);
	return frac(a[i].y) - k * frac(a[i].x);
}

void solve() {
	scanf("%lld", &n);
	for (int i = 1; i <= n; ++i) {
		scanf("%lld%lld%lld", &a[i].x, &a[i].y, &a[i].z);
	}
	ll ans = -1;
	sort(a + 1, a + n + 1, [&](node a, node b) {
		return a.x < b.x;
	});
	map<frac, ll> M;
	for (int i = 1, j = 1; i <= n; i = (++j)) {
		while (j < n && a[j + 1].x == a[i].x) {
			++j;
		}
		for (int k = i; k <= j; ++k) {
			for (int l = k + 1; l <= j; ++l) {
				frac mid(a[k].y + a[l].y, 2);
				if (M.find(mid) != M.end()) {
					ans = max(ans, M[mid] + a[k].z + a[l].z);
				}
			}
		}
		for (int k = i; k <= j; ++k) {
			for (int l = k + 1; l <= j; ++l) {
				frac mid(a[k].y + a[l].y, 2);
				M[mid] = max(M[mid], a[k].z + a[l].z);
			}
		}
	}
	M.clear();
	sort(a + 1, a + n + 1, [&](node a, node b) {
		return a.y < b.y;
	});
	for (int i = 1, j = 1; i <= n; i = (++j)) {
		while (j < n && a[j + 1].y == a[i].y) {
			++j;
		}
		for (int k = i; k <= j; ++k) {
			for (int l = k + 1; l <= j; ++l) {
				frac mid(a[k].x + a[l].x, 2);
				if (M.find(mid) != M.end()) {
					ans = max(ans, M[mid] + a[k].z + a[l].z);
				}
			}
		}
		for (int k = i; k <= j; ++k) {
			for (int l = k + 1; l <= j; ++l) {
				frac mid(a[k].x + a[l].x, 2);
				M[mid] = max(M[mid], a[k].z + a[l].z);
			}
		}
	}
	map< frac, vector<pii> > mp;
	for (int i = 1; i <= n; ++i) {
		for (int j = i + 1; j <= n; ++j) {
			if (a[i].x == a[j].x || a[i].y == a[j].y) {
				continue;
			}
			frac k1(a[j].y - a[i].y, a[j].x - a[i].x);
			mp[k1].pb(i, j);
		}
	}
	for (auto pp : mp) {
		frac k1 = pp.fst;
		map<frac, ll> M;
		vector<pii> vc = pp.scd;
		sort(vc.begin(), vc.end(), [&](pii a, pii b) {
			return getb(a.fst, a.scd) < getb(b.fst, b.scd);
		});
		int len = (int)vc.size();
		for (int i = 0, j = 0; i < len; i = (++j)) {
			while (j + 1 < len && getb(vc[j + 1].fst, vc[j + 1].scd) == getb(vc[i].fst, vc[i].scd)) {
				++j;
			}
			for (int k = i; k <= j; ++k) {
				frac mx(a[vc[k].fst].x + a[vc[k].scd].x, 2), my(a[vc[k].fst].y + a[vc[k].scd].y, 2);
				frac k2(-k1.y, k1.x);
				frac fr = my - mx * k2;
				if (M.find(fr) != M.end()) {
					ans = max(ans, M[fr] + a[vc[k].fst].z + a[vc[k].scd].z);
				}
			}
			for (int k = i; k <= j; ++k) {
				frac mx(a[vc[k].fst].x + a[vc[k].scd].x, 2), my(a[vc[k].fst].y + a[vc[k].scd].y, 2);
				frac k2(-k1.y, k1.x);
				frac fr = my - mx * k2;
				M[fr] = max(M[fr], a[vc[k].fst].z + a[vc[k].scd].z);
			}
		}
	}
	printf("%lld\n", ans);
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,vc,frac,Beginner,Trapezium,int,scd,return,const
From: https://www.cnblogs.com/zltzlt-blog/p/17484205.html

相关文章

  • AtCoder Beginner Contest 249 G Xor Cards
    洛谷传送门AtCoder传送门好题。套路地,考虑枚举最优解的\(a\)异或和二进制下与\(k\)的\(\text{LCP}\),设在第\(i\)位不同。这样的好处是\(i\)之后的位可以随便选。之后按位贪心确定最优解\(b\)的异或和。考虑之前的答案是\(res\),当前在确定第\(j\)位,如何判断\(r......
  • AtCoder Beginner Contest 305 题解 A - F
    A-WaterStation题目大意找到离给定的数最近的一个\(5\)的倍数输出即可。解题思路我们取这个数对\(5\)的上下界,也就是整数除以\(5\)再乘以\(5\),以及这个数再加上一个\(5\),比较这两数和给定数的距离即可。ACCode#include<iostream>#include<algorithm>#includ......
  • AtCoder Beginner Contest 219 H Candles
    洛谷传送门AtCoder传送门套路化了。比较显然的关路灯型区间dp。考虑你\(t\)时刻熄灭一个初始长度为\(a\)的蜡烛,得分是\(\max(a-t,0)\),所以尝试把时间塞进状态。设\(f_{i,j,k,0/1}\)表示,熄灭完区间\([i,j]\)的蜡烛,当前时间是\(t\),在左端点还是右端点的最大得......
  • AtCoder Beginner Contest 223 H Xor Query
    洛谷传送门AtCoder传送门考虑一个无脑做法:线段树维护区间线性基。时间复杂度是\(O(m\logn\log^2V)\),过于优秀以至于无法接受。事实上我们并不需要维护区间线性基,因为不带修。考虑“可持久化线性基”,开\(n\)个线性基,第\(i\)个维护前缀\([1,i]\)的数。并且插入线性......
  • AtCoder Beginner Contest 215 H Cabbage Master
    洛谷传送门AtCoder传送门考虑第一问。发现这个东西长得很像二分图匹配,考虑建图,第\(i\)个盒子建\(b_i\)个左部点,第\(i\)个球建\(a_i\)个右部点,每个盒子的每个点往可以放的球的每个点连边。显然要求能被满足等价于,这个二分图存在一个左部点的完全匹配。因为一个盒子的......
  • AtCoder Regular Contest 141 C Bracket and Permutation
    洛谷传送门AtCoder传送门考虑给出\(S\),如何求\(P,Q\)。先考虑\(P\),那我们肯定想让\(P\)的每一项都尽量往前靠。设\([1,k]\)为合法括号串,\(S_{k+1}=\texttt{)}\),那\(P\)的前\(k\)项依次为\(1\simk\),第\(k+1\)项不能为\(k+1\)了,那找到\(k+1\)之......
  • AtCoder Beginner Contest 273(E)
    AtCoderBeginnerContest273(E)E(链式结构,思维)E题目大意就是原本有一个空的序列,我们后面会进行\(q\)次操作,每次操作我们都需要输出此时的序列的最后数字下面有几种操作\(ADD\)\(x\),代表在这在这个序列的最后面添加一个\(x\)\(DELETE\),代表如果此时的序列存在数字的话,......
  • AtCoder Beginner Contest 265 F Manhattan Cafe
    洛谷传送门AtCoder传送门考虑dp,\(f_{i,j,k}\)表示考虑到第\(i\)维,\(\sum\limits_{x=1}^i|p_x-r_x|=j,\sum\limits_{x=1}^i|q_x-r_x|=k\)的方案数。转移是容易的,枚举\(r_i\)即可,\(f_{i,j,k}=\sum\limits_rf_{i-1,j-|p_i-r|,k-|q_i-r|}......
  • Atcoder Beginner Contest 301
    A-OverallWinner题目大意A和T两人玩游戏,给定一串只由A和T组成的字符串,如果第i个字符是A,则A赢得第i轮的胜利,反之则T赢;当遍历完整个字符串后,谁赢的轮数多谁就是最终赢家,如果一样则谁最先达到该轮数谁赢,输出赢家的名字解题思路签到题不多嗦了神秘代码......
  • AtCoder Beginner Contest 278 ABCDE
    AtCoderBeginnerContest278A-ShiftProblemStatement题意:给你一个长度为n的序列,让你移走前面k个后面补k个0。Solution思路:按照题意模拟即可。#include<bits/stdc++.h>usingnamespacestd;inta[1100];intmain(){ intn,k; cin>>n>>k; k=min(k,n); for(int......