Difference between Triplets POJ - 3244

题意

对于每一个三元组: T a = ( I a , J a , K a ) , T b = ( I b , J b , K b ) T_a=(I_a,J_a,K_a),T_b=(I_b,J_b,K_b) Ta=(Ia,Ja,Ka),Tb=(Ib,Jb,Kb)定义:
D ( T a , T b ) = max ⁡ { I a − I b , J a − J b , K a − K b } − min ⁡ { I a − I b , J a − J b , K a − K b } D(T_a,T_b)=\max\{I_a-I_b,J_a-J_b,K_a-K_b\}-\min\{I_a-I_b,J_a-J_b,K_a-K_b \} D(Ta,Tb)=max{IaIb,JaJb,KaKb}min{IaIb,JaJb,KaKb}
∑ i = 1 N ∑ j = i + 1 N D ( T i , T j ) \sum_{i=1}^{N}{\sum_{j=i+1}^{N}{D(T_i,T_j)}} i=1Nj=i+1ND(Ti,Tj) 的值。
数据范围: N ≤ 2 × 1 0 5 N\leq 2\times 10^5 N2×105,每个元素的范围: [ − 1 0 6 , 1 0 6 ] [-10^6,10^6] [106,106]

分析

关键在于公式的化简:
max ⁡ ( a , b , c ) − min ⁡ ( a , b , c ) = ∣ a − b ∣ + ∣ a − c ∣ + ∣ b − c ∣ 2 \max(a,b,c)-\min(a,b,c)=\frac{|a-b|+|a-c|+|b-c|}{2} max(a,b,c)min(a,b,c)=2ab+ac+bc
代入三元组,可得:
D ( T a , T b ) = ∣ ( I a − J a ) − ( I b − J b ) ∣ + ∣ ( J a − K a ) − ( J b − K b ) ∣ + ∣ ( I a − K a ) − ( I b − K b ) ∣ 2 D(T_a,T_b)=\frac{|(I_a-J_a)-(I_b-J_b)|+|(J_a-K_a)-(J_b-K_b)|+|(I_a-K_a)-(I_b-K_b)|}{2} D(Ta,Tb)=2(IaJa)(IbJb)+(JaKa)(JbKb)+(IaKa)(IbKb)
现在,我们要想办法去掉绝对值。对每个 T i T_i Ti,求出 ( I i − J i ) , ( I i − K i ) , ( J i − K i ) (I_i-J_i),(I_i-K_i),(J_i-K_i) (IiJi),(IiKi),(JiKi),然后分别从小到大排序。对于 ( I i − J i ) (I_i-J_i) (IiJi),假设它出现在排列后的第 x x x 个位置,那么他对最后的答案会有 x − 1 x-1 x1 个正的贡献, n − x n-x nx 个负的贡献,最终的贡献为 2 x − n − 1 2x-n-1 2xn1。对其它两个同样处理,即可得到结果。

代码

#include <cstdio>
#include <algorithm>
#include <set>
#include <iostream>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int a[N],b[N],c[N];
int main(){
    int n;
    while(scanf("%d",&n),n!=0){
        for(int i=1;i<=n;i++){
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            a[i]=x-y;
            b[i]=x-z;
            c[i]=y-z;
        }
        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+=1LL*(2*i-n-1)*a[i];
            ans+=1LL*(2*i-n-1)*b[i];
            ans+=1LL*(2*i-n-1)*c[i];
        }
        printf("%lld\n",ans/2);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值