hdu 4631(增量最近点对)

本文介绍了一种解决最近点对问题的经典算法变形。通过使用multiset维护x坐标有序表,并结合特定条件下的枚举更新策略,实现了高效求解。适用于随机数据集,提供完整代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接

CLJ神犇的题目, 其实这题解法并不难, 算是个经典问题解法的简单变形吧, 对于最近点对这个问题, 一般有两种做法, 有一种针对随机数据很快的O(n ^ 2)解法, 还有一种严格O(n * log(n))的分治算法, 对于一般的题目前者会比较快,如果不熟悉这两种做法可以参考http://www.csie.ntnu.edu.tw/~u91029/PointLinePlane2.html 而这道题目的解法其实就是前种解法的变形,  用一个multiset来维护以x为关键字的有序表, 每次插入一个点之前分情况枚举更新答案直到不可能更新。。。。


#include <vector>
#include <queue>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>

using namespace std;

const int N = 500005;

typedef long long LL;
const LL INF = 1LL << 60;

#define DB cout << "Yes" << endl;
#define DB2 cout << "No" << endl;

inline int readint() {
	char c = getchar();
	while (!isdigit(c)) c = getchar();

	int x = 0;
	while (isdigit(c)) {
		x = x * 10 + c - '0';
		c = getchar();
	}

	return x;
}

int buf[10];

inline void writeint(int x) {
	int p = 0;
	if (x == 0) p++;
	else while (x) {
		buf[p++] = x % 10;
		x /= 10;
	}
	for (int j = p - 1; j >= 0; j--)
		putchar('0' + buf[j]);
}

struct Point {
	LL x, y;

	bool operator < (const Point& p) const {
		return x < p.x;
	}
}p[N];

LL dist(const Point& a, const Point& b) {
	return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y);
}

multiset<Point> S;
multiset<Point>::iterator it, tmp;

inline LL pow2(int x) {
	return (LL)x * x;
}

int main() {
	int test, ax, bx, cx, ay, by, cy, n;	
	test = readint();

	while (test--) {
		n = readint(), ax = readint(), bx = readint(), cx = readint();
		ay = readint(), by = readint(), cy = readint();

		S.clear();
		p[0].x = 0, p[0].y = 0;

		LL res = 0;
		int m;

		LL d = INF;
		int minX, maxX;

		for (int i = 1; i <= n; i++) {
			p[i].x = (p[i - 1].x * ax + bx) % cx;
			p[i].y = (p[i - 1].y * ay + by) % cy;

			if (i == 1) {
				S.insert(p[i]);
				continue;
			}

			if (d == 0) break;

			minX = S.begin()->x;
			it = S.end();
			it--;
			maxX = it->x;

			if (p[i].x <= minX) {
				for (it = S.begin(); it != S.end(); it++) {
					if (pow2(it->x - p[i].x) >= d) break;
					d = min(dist(*it, p[i]), d);					
				}	
			}
			else if (p[i].x >= maxX) {
				while (1) {
					if (pow2(it->x - p[i].x) >= d) break;
					d = min(dist(*it, p[i]), d);
					if (it == S.begin()) break;
					it--;
				}
			}
			else {
				tmp = S.lower_bound(p[i]);
				for (it = tmp; it != S.end(); it++) {
					if (pow2(it->x - p[i].x) >= d) break;
					d = min(dist(*it, p[i]), d);
				}
				
				if (tmp != S.begin()) {
					it = tmp;
					it--;	
					while (1) {
						if (pow2(it->x - p[i].x) >= d) break;
						d = min(dist(*it, p[i]), d);
						if (it == S.begin()) break;
						it--;
					}
				}				
			}	

			S.insert(p[i]);	
			res += d;
		}

		printf("%I64d\n", res);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值