题意简要是:在平面上住着一些人,家都是在整数坐标。现在邀请一些人来参加聚会,聚会的地点在这些人中的某一个家。两点的距离为,from (x1, y1) to (x2, y2) is |x1 - x2| + |y1 - y2|.
假设聚会地点选定了,如何计算所有人到这的距离呢?
最直观的就是遍历所有的人,每个都计算一次距离,加起来就可以了。这个算法的复杂度是O(n^2),这个办法可以通过small数据量的。
考虑到
两点的距离分别是横纵坐标的差值绝对值之和,这样就可以在计算的时候对横纵坐标分别计算,然后加起来得到总值。
当只考虑x轴的时候,先把x坐标相同的人加在一块,问题变成某一些坐标上有很多人,计算让这些人全部聚集到某一点的距离和。
就变成这样了:{(x0, p0), (x1, p1), ..., (xm, pm)}, x表示坐标,p表示这个坐标上ren的个数,求在某个坐标时(肯定是x中的某一个)的距离和。
求和的话可以做一些预处理,让计算复杂度变成常数的。先按x排序,然后求出每个坐标到x0的距离和、人数和。得到{(x0, p0, totalP0, totalV0), (x1, p1, totalP1,totalV1), ..., (xm, pm, totalPm, totalVm)},totalPk表示从x0开始到xk的所有人数和,totalVk表示这些人全部聚集到x0的距离和。
然后如何计算所有人到xk的距离和呢?
考虑大于xk的所有人,即totalPm - totalPk, 这些人到x0的距离和是totalVm - totalVk, 然后到xk的距离和再减去xk到x0的距离totalVm - totalVk - (totalPm - totalPk) * (xk - x0)。这样就计算出大于xk的所有人之和。小于xk的呢?按照同样的办法,我们先计算出所有人到xk的距离和、人数和,然后常数的就计算出小于xk的所有人之和了。
对于y轴是一样的计算。
这样通过预处理后,计算所有人到某一个坐标的距离和变成了常数的。O(N)的复杂度就可以通过large数据量了。代码如下:
import java.io.*;
import java.util.*;
import java.util.Map.Entry;
public class HelloWorld {
static class Node implements Comparable<Node> {
long location;
long person;
long leftPerson;
long leftValue;
long rightPerson;
long rightValue;
Node () {
}
Node(long x) {
location = x;
}
@Override
public int compareTo(Node o) {
long ret = location - o.location;
if (ret == 0) return 0;
return ret < 0? -1 : 1;
}
}
public static void main(String[] args) {
try {
// BufferedReader br = new BufferedReader(new FileReader("D:/codejam/a.txt"));
// BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
// BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-small-practice.in"));
// BufferedWriter bw = new BufferedWriter(new FileWriter("D:/codejam/B-small-result.txt"));
// BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-small-attempt1.in"));
BufferedReader br = new BufferedReader(new FileReader("D:/codejam/B-large-practice.in"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/codejam/B-large-result.txt"));
String line;
line = br.readLine();
int T = Integer.parseInt(line);
for (int cas = 1; cas <= T; cas++) {
Map<Long, Long> xMap = new TreeMap<Long, Long>();
Map<Long, Long> yMap = new TreeMap<Long, Long>();
line = br.readLine();
int B = Integer.parseInt(line);
long[] all = new long[1000000 * 2];
int len = 0;
for (int i = 0; i < B; i++) {
line = br.readLine();
String[] tmp = line.split(" ");
long sx = Long.parseLong(tmp[0]);
long sy = Long.parseLong(tmp[1]);
long nx = Long.parseLong(tmp[2]);
long ny = Long.parseLong(tmp[3]);
for (long x = sx; x <= nx; x++) {
long value = 0;
if (xMap.containsKey(x)) {
value = xMap.get(x) + ny - sy + 1;
} else {
value = ny-sy+1;
}
xMap.put(x, value);
}
for (long y = sy; y <= ny; y++) {
long value = 0;
if (yMap.containsKey(y)) {
value = yMap.get(y) + nx - sx + 1;
} else {
value = nx - sx + 1;
}
yMap.put(y, value);
}
for (long x = sx; x <= nx; x++)
for (long y = sy; y <= ny; y++) {
all[len++] = x;
all[len++] = y;
}
}
ArrayList<Node> xList = new ArrayList<Node>();
ArrayList<Node> yList = new ArrayList<Node>();
build(xMap, xList);
build(yMap, yList);
long ret = Long.MAX_VALUE;
long rx = 0;
long ry = 0;
for (int i = 0; i < len ;i+=2) {
long x = all[i];
long y = all[i+1];
long tmp = 0;
tmp += compute(xList, x);
tmp += compute(yList, y);
if (tmp < ret || (tmp == ret && (x < rx || (x == rx && y < ry)))) {
ret = tmp;
rx = x;
ry = y;
}
}
bw.write("Case #" + cas +": " + rx + " " + ry + " " + ret);
bw.newLine();
bw.flush();
}
br.close();
bw.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
private static long compute(ArrayList<Node> xList, long x) {
int n = xList.size();
long ret = 0;
int lo = Collections.binarySearch(xList, new Node(x));
Node last = xList.get(n-1);
Node first = xList.get(0);
Node node = xList.get(lo);
ret += last.leftValue - node.leftValue - (last.leftPerson - node.leftPerson) * (node.location - first.location);
ret += first.rightValue - node.rightValue - (first.rightPerson - node.rightPerson) * (last.location - node.location);
return ret;
}
private static void build(Map<Long, Long> xMap, ArrayList<Node> xList) {
Iterator<Entry<Long, Long>> iter = xMap.entrySet().iterator();
while (iter.hasNext()) {
Entry<Long, Long> entry = iter.next();
Node x = new Node();
x.location = entry.getKey();
x.person = entry.getValue();
xList.add(x);
}
Node node = xList.get(0);
node.leftPerson = node.person;
node.leftValue = 0;
int n = xList.size();
long firstLocation = node.location;
for (int i = 1; i < n; i++) {
node = xList.get(i);
node.leftPerson += xList.get(i-1).leftPerson + node.person;
node.leftValue += xList.get(i-1).leftValue + (node.person * (node.location - firstLocation));
}
node = xList.get(n-1);
node.rightPerson = node.person;
node.rightValue = 0;
long lastLocation = node.location;
for (int i = n - 2; i>=0; i--) {
node = xList.get(i);
node.rightPerson += xList.get(i+1).rightPerson + node.person;
node.rightValue += xList.get(i+1).rightValue + (node.person * (lastLocation - node.location));
}
}
}