前言
“少小离家老大回,安能辨我是雄雌。 ”今天,嘟嘟老师讲一道看上去难实际很简单的题——旅行者。
题目描述
Smart是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行。Smart想去参观n个目的地(都在一条直道上)。Smart在起点开始他的旅行。第i个目的地和起点的距离为a[i]千米(a[i]为非负整数)。不存在两个目的地和起点的距离相同。
从第i个目的地走到第j个目的地所走的路程为 |a[i]-a[j]|千米。我们把参观n个目的地的顺序称作一次“旅行”。Smart可以参观他想要参观的任意顺序,但是每个目的地有且只能被参观一次(参观顺序为n的排列)。
Smart把所有可能的“旅行”都写在一张纸上,并且记下每个“旅行”所要走的路程。他对所有“旅行”的路程之和的平均值感兴趣。但是他觉得计算太枯燥了,所以就向你寻求帮助。
输入
第一行一个正整数n。
第二行n个非负整数a[1],a[2],….,a[n](1≤a[i]≤10^7)。
输出
两个整数,答案用最简分数形式输出,第一个为分子,第二个为分母。
样例输入
2 3 5
样例输出
22 3
样例说明
样例有6种可能的旅行:
[2, 3, 5]: 该“旅行”的路程:|2 – 0| + |3 – 2| + |5 – 3| = 5;
[2, 5, 3]: |2 – 0| + |5 – 2| + |3 – 5| = 7;
[3, 2, 5]: |3 – 0| + |2 – 3| + |5 – 2| = 7;
[3, 5, 2]: |3 – 0| + |5 – 3| + |2 – 5| = 8;
[5, 2, 3]: |5 – 0| + |2 – 5| + |3 – 2| = 9;
[5, 3, 2]: |5 – 0| + |3 – 5| + |2 – 3| = 8。
答案为 1/6 *(5+7+7+8+9+8)=44/6=22/3。
数据范围限制
30%的数据:n≤10;
50%的数据: n≤1000;
100%的数据:n≤100000。
思路
此题很多人尝试去枚举,不过后来是怎么也暴力不出来的。这时候,就只能循环一步一步推。首先来个快排,然后算出a[1]…a[n]之间的和(暂用ans表示),之后循环,每个点的找一遍,ans:=ans+(n-i*2+1)*a[i]*2;之后算出他们的最大公因数,约分后输出最简分数就行了。
代码
var
a:array[1..100000] of int64;
i,n:longint;
ans:int64;
procedure sb(l,r:longint);
var
i,j:longint;
k,p:int64;
begin
i:=l;
j:=r;
k:=a[(l+r) div 2];
while (i<j) do
begin
while (a[i]>k) and (i<r) do inc(i);
while (a[j]<k) and (l<j) do dec(j);
if (i<=j) then
begin
p:=a[i];
a[i]:=a[j];
a[j]:=p;
inc(i);
dec(j);
end;
end;
if (i<r) then sb(i,r);
if (l<j) then sb(l,j);
end;
function lsb(x,y:int64):int64;
var
z:int64;
begin
repeat
z:=x mod y;
x:=y;
y:=z;
until z=0;
lsb:=x;
end;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]);
inc(ans,a[i]);
end;
sb(1,n);
for i:=1 to n do
ans:=ans+(n-i*2+1)*a[i]*2;
write(ans div lsb(ans,n),' ',n div lsb(ans,n));
end.