【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

 

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