codeforces 340CTourist Problem(找規律數學題)

果7發表於2013-10-07
C. Tourist Problem
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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 sequencea1a2, ..., 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 a1a2, ..., 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.

Sample test(s)
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  =  = .


題目大意:看下面的資料即可知道題目的意思。沒有想到把長度全部轉化為兩個端點之間的距離。然後就會找到規律,不過由於0確定為起點所以情況要分為兩類。

下面的大部分文字源自於Thousand Sunny,我做了些許改動。


1、以n=3序列{a1,a2,a3}為例,實際上是{0,a1,a2,a3},起點確定,總共有n!中方案。

2、經過簡單的思考就可以發現,每種方案的第一步比較特殊,因此分類討論:

  一、0->ak:這條線段會出現
(n-1)!次,由於0必須是起點,ak為第一個點,其它的n-1個點的全排列!那麼所有方案的第一步之和=(0->a1)*(n-1)!+(0->a2)*(n-1)!+(0->a3)*(n-1)!=(a1+a2+a3)*(n-1)!

  二、ai->aj:既然是線段,在序列上必然是連續出現。形如ai->aj的線段會出現在第2步~第n步的任意一處位置,出現的次數為
(n-2)!,然後採取0到最後一個沒取的an之間插空,共有i-1種。所以ai->aj出現的總次數為(n-1)*(n-2)!=(n-1)!,那麼所有方案的第2步~第n步之和=(a1->a2)*(n-1)!+(a2->a1)*(n-1)!+(a1->a3)*(n-1)!+(a3->a1)*(n-1)!+(a2->a3)*(n-1)!+(a3->a2)*(n-1)!=2*(|a1-a2|+|a1-a3|+|a2-a3|)*(n-1)!

3、“一”與“二”之和就是總路程,約掉(n-1)!後,答案就是:[(a1+...+an)+2*(∑|ai-aj|)]/n,(i!=j)

4、由於資料範圍是105,直接列舉計算|ai-aj|會超時。

  注意:計算|ai-aj|實際上就是計算序列{a1,a2,a3,a4}任意兩條線段的長度之和。利用ai->aj覆蓋了ai->a(j-1),從左向右觀察,則以a2結束的線段只有S1=a1->a2,以a3結束的線段有a1->a3,a2->a3,其中a1->a3可以看做a1->a2+a2->a3,這裡a1->a2已經計算好了,所以S2=S1+2*(a2->a3)。同理,以a4結束的線段有a1->a4,a2->a4,a3->a4,不考慮a3->a4,其餘的均是將以a3結束的線段延長a3->a4,所以S3=S2+3*(a3->a4)。具體可以自己在紙上畫畫,很容易找到規律!

  狀態方程:Si=S(i-1)+i*|ai-a(i+1)|

注意:

1、long long T^T

2、給出的序列是亂序的


題目地址:C. Tourist Problem

AC程式碼:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
using namespace std;
int a[100005];

__int64 gcd(__int64 m,__int64 n)
{
    __int64 tmp;
    while(n)
    {
        tmp=m%n;
        m=n;
        n=tmp;
    }
    return m;
}

int main()
{
    int n,i;
    __int64 sum,sum1,sum2;
    while(~scanf("%d",&n))
    {
        sum=sum1=sum2=0;
        for(i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum1+=a[i];
        }
        sort(a,a+n+1);
        __int64 tmp=0;
        for(i=1;i<n;i++)
        {
            tmp+=(a[i+1]-a[i])*i;
            sum2+=tmp<<1;
        }
        
        //sum1第一類的和,sum2第二類的和
        sum=sum1+sum2;
        tmp=gcd(sum,n);
        printf("%I64d %I64d\n",sum/tmp,n/tmp);
    }
    return 0;
}



相關文章