poj 3244 找规律

题意:定义两个三元组(xi, yi, zi)和(xj, yj, zj),他们的距离为dist =  max( xi-xj, yi-yj, zi-zj) - min(xi-xj, yi-yj, zi-zj),给定n个三元组(n<=200000),求任意两个三元组的距离之和。

令a=xi-xj,b=yi-yj,c=zi-zj,问题转化为dist = max(a, b, c) - min(a, b, c),考虑数轴上的三个点a b c,  dist为它们覆盖的线段长度。dist = ( |a-b| + |b-c| + |c-a| ) / 2。这样一来就不用考虑a b c 谁大谁小。。

所以dist = (  | (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。

令ai=xi-yi, bi=yi-zi, ci=zi-xi,   dist = ( |ai-aj| + |bi-bj| + |ci-cj| ) / 2,其中a b c可以分开求。

例如求a,先从小到大排序,考虑排序后的a[i],前面有 i 个比a[i]小的数,a[i]要减去它们,于是a[i]贡献了 i 次正数;后面有n-1-i个比a[i]大的数,每个数都要减a[i],a[i]贡献了n-1-i 次负数。 

 

 

const int M = 200005;
int n, x, y, z;
int a[M], b[M], c[M];

LL ans;

int main(){
    #ifndef ONLINE_JUDGE
    freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    #endif

    while( scanf("%d", &n), n ){
        FOR(i, 0, n){
            scanf("%d%d%d", &x, &y, &z);
            a[i] = x-y; b[i] = y-z; c[i] = z-x;
        }
        sort(a, a+n); sort(b, b+n); sort(c, c+n);

        ans = 0;
        FOR(i, 0, n) ans += (LL)((i<<1)-1-n) * ( a[i] + b[i] + c[i] );

        printf("%I64d\n", ans>>1);
    }

    return 0;
}

 

posted @ 2013-05-17 17:59  心向往之  阅读(248)  评论(0)    收藏  举报