【NOIP2013模拟联考9】旅行者问题

problem

Description

lahub是一个旅行者的粉丝,他想成为一个真正的旅行者,所以他计划开始一段旅行。lahub想去参观n个目的地(都在一条直道上)。lahub在起点开始他的旅行。第i个目的地和起点的距离为ai千米(ai为非负整数)。不存在两个目的地和起点的距离相同。

从第i个目的地走到第j个目的地所走的路程为 |ai-aj|千米。我们把参观n个目的地的顺序称作一次“旅行”。lahub可以参观他想要参观的任意顺序,但是每个目的地有且只能被参观一次(参观顺序为n的排列)。

lahub把所有可能的“旅行”都写在一张纸上,并且记下每个“旅行”所要走的路程。他对所有“旅行”的路程之和的平均值感兴趣。但是他觉得计算太枯燥了,所以就向你寻求帮助。

Input

第一行一个正整数n。

第二行n个非负整数a1,a2,…,an(1≤ai≤10^7)。

Output

两个整数,答案用最简分数形式输出,第一个为分子,第二个为分母。

Sample Input

3

2 3 5

Sample Output

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 × \frac 16× 61×(5+7+7+8+9+8)= 44 6 \frac {44}6 644 = 22 3 \frac {22}3 322

Data Constraint

30% n<=10

50% n<=1000

100% n<=100000

思路

首先将数据从小到大排序,就不用考虑绝对值的问题了。
这道题分为分母和分子两个部分讨论,显然,分母为 n ! n! n!
如果我们设第0个位置为0,接下来分子又可以分为两种情况:
1 . 0 → a i 0\to a_i 0ai,可得:
s u m 1 = ∑ a i sum1=\sum a_i sum1=ai t o t 1 = s u m 1 × ( n − 1 ) ! tot1=sum1×(n-1)! tot1=sum1×(n1)!
2 . a i → a j a_i\to a_j aiaj,可得:
s u m 2 = 2 × ∑ ( a i − a j ) sum2=2×\sum(a_i-a_j) sum2=2×(aiaj) t o t 2 = s u m 2 × ( n − 1 ) ! tot2=sum2×(n-1)! tot2=sum2×(n1)!
这些公式的证明过程在这里就不赘述了。
将上述公式合成答案即为: t o t 1 + t o t 2 n ! \frac {tot1+tot2}{n!} n!tot1+tot2
接着:
( n − 1 ) ! × ( s u m 1 + s u m 2 ) n ! \frac {(n-1)!×(sum1+sum2)}{n!} n!(n1)!×(sum1+sum2)
l a s t : last: last
s u m 1 + s u m 2 n \frac {sum1+sum2}n nsum1+sum2
公式推来了,但时间复杂度的问题还没有解决。
∑ a i \sum a_i ai求值的时间复杂度是 O ( n ) O(n) O(n)。但 ∑ ( a i − a j ) \sum (a_i-a_j) (aiaj)复杂度为 O ( n 2 ) O(n^2) O(n2),会TLE。接下来要考虑的就是 ( a i − a j ) (a_i-a_j) (aiaj)的求值方式。
由于 a i a_i ai只会减 ∑ k = 1 i − 1 a k \sum^{i-1}_{k=1} a_k k=1i1ak,所以每个 a i a_i ai要减的就是 a i − 1 a_{i-1} ai1的前缀和,这样就可以在 O ( n ) O(n) O(n)时间内求出。
最后将答案化为最简即可。

Code

#include<cstdio>
#include<iostream>
#define fre(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define N 100005
using namespace std;
long long n,a[N],s[N];
long long gcd(long long n,long long m)
{
    
    
	long long t;
	if(n>m) swap(n,m);
	while(n!=0)
	{
    
    
		t=m%n;
		m=n;
		n=t;
	}
	return m;
}
void qsort(int l,int r)
{
    
    
	int i=l,j=r,mid=a[(l+r)/2];
	while(i<=j)
	{
    
    
		while(a[i]<mid) i++;
		while(a[j]>mid) j--;
		if(i<=j)
		{
    
    
			long long t;
			t=a[i],a[i]=a[j],a[j]=t;
			i++,j--;
		}
	}
	if(l<j) qsort(l,j);
	if(i<r) qsort(i,r);
}
int main()
{
    
    
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	qsort(1,n);
	for(int i=1;i<=n;i++)
		s[i]=s[i-1]+a[i];
	long long s1=0,s2=0;
	for(int i=1;i<=n;i++)
		s1+=a[i],s2+=2*(a[i]*(i-1)-s[i-1]);
	long long s3=s1+s2,gd;
	gd=gcd(s3,n);
	printf("%lld %lld",s3/gd,n/gd);
}

猜你喜欢

转载自blog.csdn.net/weixin_46830417/article/details/112061749