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; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)