传送门
平面最近点对模型
给出平面上n个点,找出其中一对点的距离,使得在这n个点的所有点对中,该距离为所有点对中最小的
分治法求
(g(i,j))就是求区间[i + 1, j]的区间的值,也就是前缀和表示(sum[j] - sum[i])
那么转换为((j - i) ^ 2 + (sum[j] - sum[i]) ^ 2)
那么对于n个点,x就是i,y就是前缀和
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#define ll long long
using namespace std;
const int N = 1e6 + 5;
const ll Inf = 1e13;
struct Point {
ll x, y;
Point (int X = 0, int Y = 0) { x = X, y = Y;}
} p[N], Q[N];
bool cmpx(Point a, Point b) {return a.x < b.x || (a.x == b.x && a.y < b.y);}
bool cmpy(Point a, Point b) {return a.y < b.y;}
ll dis(Point a, Point b) {
return pow(a.x - b.x, 2) + pow(a.y - b.y, 2);
}
ll Merge(int l, int r) { // O(nlogn)
ll ans = Inf;
if (l == r) return ans;
if (l + 1 == r) return dis(p[l], p[r]);
int mid = (l + r) / 2;
ll d1 = Merge(l, mid);
ll d2 = Merge(mid + 1, r);
ans = min(d1, d2); // 当前最小的
ll d = sqrt(ans);
int k = 0;
for (int i = mid; i >= l; i --) { // 找到更短的
if (p[mid].x - p[i].x > d) break;
Q[++k] = p[i];
}
for (int i = mid + 1; i <= r; i ++) { // 找到更短的
if (p[i].x - p[mid].x > d) break;
Q[++k] = p[i];
}
sort(Q + 1, Q + k + 1, cmpy);
for (int i = 1; i < k; i++) { // 暴力求
for (int j = i + 1 ; j <= k && Q[j].y - Q[i].y <= d; j++) {
ans = min(ans, dis(Q[i], Q[j]));
}
}
return ans;
}
int main() {
int n;
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%lld", &p[i].y);
p[i].x = i;
}
for(int i = 2; i <= n; i++) p[i].y += p[i - 1].y;
sort(p + 1, p + n + 1, cmpx);
printf("%lld
", Merge(1, n));
return 0;
}