POJ - 3244-Difference between Triplets

其实我最开始没有这道题。。。是做到UPC-11079-小P的决斗,训练结束后然后搜索了一波,才了解这个题的。

非常牛逼的题。。。这么多人做出来了。。。我好菜。。。

对于每对三元组Ta=(La,Ja,Ka),Tb=(Lb,Jb,Kb),定义Ta,Tb之间的差值D为D(Ta,Tb)=max(La−Lb,Ja−Jb,Ka−Kb)−min(La−Lb,Ja−Jb,Ka−Kb),

给多个三元组,求两两之间差值之和。

给出一个转化 max,min与绝对值之间的转化:

max(a,b,c)-min(a,b,c)=(|a-b|+|b-c|+|c-a|)/2

证明这个式子:给定一个递增的序列,a1,a2,a3,a4...an

 max(a1,a2,a3...an)-min(a1,a2,a3...an)

 =1/2(an-a1+an-a1)=an-an-1+an-1-an-2....-a2+a2-a1+an-a1

 =1/2(|an-an-1|+|an-1-an-2|+...+|a2-a1|+|a1-an|) 

这玩意是严重对称的。。。然后。。。我也不是很清楚了

 知道这个性质以后,我们考虑一个叫贡献的东西,首先肯定把

 a=xi-yi b=yi-zi c=zi-xi  保存下来。

 首先绝对值是非常讨厌的,我们通过排序去掉了绝对值。

 然后我们考虑这样一个东西,当前是i位置,那么前面的都是比我小的,所以再对于前面i-1匹配时,a[i]做的是被减数,因此a[i]*(i-1)

  对于后面n-i-1个数,我们发现它是做减数,那么贡献其实是-(n-i)*a[i],所以单点贡献是a[i]*(i-1)-(n-i)*a[i],对与其他的也是一样的。

  

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#define LL long long
using namespace std;
const int maxx = 500005;
LL L[maxx];
LL J[maxx];
LL K[maxx];
LL a[maxx];
LL b[maxx];
LL c[maxx];
int main(){
  int n;
  while(~scanf("%d",&n)&&n){

    for (int i=1;i<=n;i++){
        scanf("%lld%lld%lld",&L[i],&J[i],&K[i]);
        a[i]=L[i]-J[i];
        b[i]=J[i]-K[i];
        c[i]=K[i]-L[i];
    }
    sort(a+1,a+1+n);
    sort(b+1,b+1+n);
    sort(c+1,c+1+n);
    LL ans=0;
    for (int i=1;i<=n;i++){
        ans+=a[i]*(i-1)-a[i]*(n-i);
        ans+=b[i]*(i-1)-b[i]*(n-i);
        ans+=c[i]*(i-1)-c[i]*(n-i);
    }
    printf("%lld\n",ans/2);
  }
  return 0;
}

 

posted @ 2019-02-22 23:02  bluefly-hrbust  阅读(189)  评论(0编辑  收藏  举报