【CodeForces - 340C】Tourist Problem (组合数学)

Iahub is a big fan of tourists. He wants to become a tourist himself, so he planned a trip. There are n destinations on a straight road that Iahub wants to visit. Iahub starts the excursion from kilometer 0. The n destinations are described by a non-negative integers sequence a1, a2, ..., an. The number ak represents that the kth destination is at distance ak kilometers from the starting point. No two destinations are located in the same place.

Iahub wants to visit each destination only once. Note that, crossing through a destination is not considered visiting, unless Iahub explicitly wants to visit it at that point. Also, after Iahub visits his last destination, he doesn't come back to kilometer 0, as he stops his trip at the last destination.

The distance between destination located at kilometer x and next destination, located at kilometer y, is |x - y| kilometers. We call a "route" an order of visiting the destinations. Iahub can visit destinations in any order he wants, as long as he visits all n destinations and he doesn't visit a destination more than once.

Iahub starts writing out on a paper all possible routes and for each of them, he notes the total distance he would walk. He's interested in the average number of kilometers he would walk by choosing a route. As he got bored of writing out all the routes, he asks you to help him.

Input

The first line contains integer n (2 ≤ n ≤ 105). Next line contains n distinct integers a1, a2, ..., an (1 ≤ ai ≤ 107).

Output

Output two integers — the numerator and denominator of a fraction which is equal to the wanted average number. The fraction must be irreducible.

Examples

Input

3
2 3 5

Output

22 3

Note

Consider 6 possible routes:

  • [2, 3, 5]: total distance traveled: |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.

The average travel distance is  =  = .

思路:

zxz大佬一眼就看出来了,是要求点的贡献,我想想好像真的是这样,可是不会啊。只好找了大佬的博客。

题目思路解法来自:大佬的博客   文章内容也是在大佬博客的基础上,加了一点自己的想法。

假设p_j中的j代表了在一个序列中的第j个位置,设p_j=i,那么p_j的值,即i就代表在有序数组a中的位置,就是下标(数组a是我们输入元素然后排序的数组)因此a_{p_j}就代表,在一种排列中的第j个位置上的值是a[i]。

所以对于任意一个排列p_1,...p_n,这个排列的距离公式就是a_{p_i}+ \sum ^{n-1}_{i=1}|a_{p_i}-a_{p_{i+1}}|

然后就是考虑每一个a_i对于结果的贡献度(数组a已经升序,接下来讨论的情况都是在此基础上的)

由上面的公式我们可以看出某个元素的贡献度和他周围相邻点的贡献度是有关系的,比如|a_{p_i}-a_{p_{i+1}}|,如果a_{p_i}>a_{p_{i+1}},那么这个式子就是a_{p_i}-a_{p_{i+1}},那么a_{p_i}的贡献度就是a_{p_i},而a_{p_{i+1}}的贡献度是-a_{p_{i+1}}

首先考虑的是第一个点对结果的贡献度,因此假设p_1=i,就是一组数的排序中a[i]这个元素是放在首位的,那么影响他的贡献度的只有第二个元素,剩下的n-2个元素随意排列,如果p_{2}>p_1,那么a_{p_{2}}>a_{p_1}(元素升序排列),这个式子就是a_{p_{2}}-a_{p_1},因此a_{p_1}的贡献就是-a_{p_1},由于之前有个a_{p_1}-0,贡献是a_{p_1},所以一加一减,贡献为0。如果p_1>p_{2},那么a_{p_1}>a_{p_{2}},其贡献为a_{p_1},两次都为加,贡献为2*a_{p_1}。因为第一种情况贡献为0,所以我们可以只考虑第二种带来的贡献,因为我们假设p_1=i,而要求p_1>p_{2},因此p_{2}可以选的值有i-1种,剩下的n-2个位置的排列有(n-2)!种,因此我们可以求得总贡献为2*(i-1)*(n-2)!*a_i

接下来是考虑最后一个位置的贡献度(思路同第一步),假设p_n=i,考虑p_{n-1}的取值,其他n−2个元素随意排列,如果p_{n-1}>p_n,那么对答案贡献是-a_i,否则的话,对答案贡献是a_i。因此这种情况对答案的贡献就是两者之和,即:(i-1)*(n-2)!*a_i+(n-i)*(n-2)!*(-a_i),(乘法的三项分别为:前一个位置的可能取值,剩下位置的排列组合,自身贡献度),合并后((i-1)-(n-i))*(n-2)!*a_i

最后是考虑在中间n-2中任何一个位置的贡献,假设p_j=i,2\leq j\leq(n-1),考虑p_{j-1}p_{j+1}的值,其他n-3个元素随意排列,如果两个数一个比p_{j}大另一个比p_{j}小。那么对答案的贡献度是0,以其中一种可能为例,三个数是p_{j-1}\leq p_j\leq p_{j+1},则根据距离公式可得p_{j+1}-p_j+p_j-p_{j-1},所以其贡献为0。如果两个都比p_j大,那么对答案贡献就是-2a_{i},如果都比p_j小,那么对答案贡献就是2a_{i},故这种情况对答案的贡献就是(n-2)*(n-3)!*(A^2_{i-1}-A^2_{n-i})*2*a_i

求得了a_i在不同位置的贡献,最后加起来就是a_i的总贡献。(n-2)!*(2*(i-1)+2*i-n-1+2*(A^2_{i-1}-A^2_{n-i}))*a_i

 

(n-1)!*(4*i-2*n-1)*a_i

总共的路径条数n!种(就是n个数随机排列形成一个序列的种类数),要求期望,所以要除以n!。

进而能够求得期望的公式为:\frac{\sum ^n_{i=1}(4*i-2*n-1)*a_i}{n}

ac代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<queue>
#include<stack>
#include<map>
#include<string.h>
#define ll long long
#define ull unsigned long long
#define mod 123456789 
using namespace std;
ll  a[101000];
int main()
{
	ll n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	sort(a+1,a+n+1);//排序 
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		ans+=(4*i-2*n-1)*a[i];
	}
	ll g=__gcd(ans,n);
	cout<<ans/g<<" "<<n/g<<endl;
	
    return 0;
}

 

以下是别的大佬用别的方法做的:

http://www.cnblogs.com/sineatos/p/3522288.html

https://blog.csdn.net/jeremy1149/article/details/56281920

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章