poj 3244

神级思维!!!

discuss中:

//定义两个三元组I(xi,yi,zi)和J(xj,yj,zj),(可以看做是空间中的点)
//他们的距离为D(I,J)=max{xi-xj,yi-yj,zi-zj}-min{xi-xj,yi-yj,zi-zj},
//给定n个三元组(n<=200000),求任意两个三元组的差的和
//抽化出来的模型是 max(a,b,c)-min(a,b,c),这个东西吧他放在数轴上 a,b,c
//我们要求最大和最小的差就是这三个点构成的线段的距离,那么我们这里再变通下 是不是端点到中间那个点的距离
//其实画出这个图的时候,就可以看到这个距离为(|a-b|+|b-c|+|c-a|)/2,这样我们并不需要关心中间的那个
//对应到题目中的原型,就是(|(xi-xj)-(yi-yj)|+|(yi-yj)-(zi-zj)|+|(zi-zj)-(xi-xj)|)/2;
//对应到同一个点上就是(|(xi-yi)-(xj-yj)|+|(yi-zi)-(yj-zj)|+|(zi-xi)-(zj-xj)|)/2;
//设a=(xi-yi),b=(yi-zi),c=(zi-xi),原问题等价为(|ai-aj|+|bi-bj|+|ci-cj|)/2;
//然后三个可以完全分开完全独立的计算,并不影响其他两元,这里要加个优化,就是按从小到大排序出来
//我们只需要算出每个位置上,他贡献了多少次加法,贡献了多少次减法即可
//举个例子,目前把a的部分排序了,对于第i个,他前面的比它小,所以在和i点比较时i点贡献了i次加,对后面的n-i个点
//向他们贡献了n-i次减法

//============================================================================
// Name        : 3244.cpp
// Author      : 
// Version     :
// Copyright   : Your copyright notice
// Description : Hello World in C++, Ansi-style
//============================================================================

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

long long a[200010], b[200010], c[200010];
long long ans;
int n, x, y, z;

int main() {
	freopen("a.txt", "r", stdin);
	while(scanf("%d", &n)&&n){
		for(int i = 1;i <= n;i++){
			scanf("%d%d%d", &x, &y, &z);
			a[i] = x-y;
			b[i] = y-z;
			c[i] = z-x;
//			printf("%d %d %d\n", a[i], b[i], c[i]);
		}
		sort(a+1, a+1+n);
		sort(b+1, b+1+n);
		sort(c+1, c+1+n);
		ans = 0;
		for(int i = 1;i <= n;i++){
//			printf("%d %d %d\n", a[i], b[i], c[i]);
			ans += (i-1+i-n)*a[i];
			ans += (i-1+i-n)*b[i];
			ans += (i-1+i-n)*c[i];
		}
		printf("%I64d\n", ans/2);
	}
	return 0;
}

  

posted @ 2011-08-03 11:03  KOKO's  阅读(203)  评论(0编辑  收藏  举报