【题意分析】
给定n个点,从原点出发,走遍所有的点(可以不按顺序走)。输出:所有的方案所行走的距离和与总方案数的比(最后的两个数需互质)。
【解题思路】
首先,先不要管数据范围——求总方案数是比较简单的,就是n!,为什么呢?首先,从0到每一个点,有n种方法。然后,剩下了(n-1)个点,因为不可能走回原点,所以还有(n-1)种走法……那么,根据乘法原理,一共有:n*(n-1)*(n-2)*……*1=n!种走法。
然后,我们来看看怎么推导所有方案所行走的距离。
1, 走第一步的时候,一共有n种走法,又因为共有n!种做法,所以,第一步从0~ai(0<i<=n)的走法分别有(n!)/n=(n-1)!种。
2, 下面是第2步到~第n步的走法。像ai~aj这样的走法,并使i,j相邻。除了这两个数以外,其他的排列就有(n-2)!种,那么,这样的i,j一共有(n-1)种走法。所以,一共有(n-2)!*(n-1)=(n-1)!种走法。假如还是不懂的话,看下面的例子:
有四个数字:1,2,3,4
选1,2:有(n-2)!种
选2,3:有(n-2)!种
……
共(n-1)种。
很明显,一共有(n-2)!*(n-1)=(n-1)!种走法。
因为有ai~aj,所以也可以有aj~ai,所以最终结果要*2。
3,接下来:我们要进行化简。
[(a1+a2+a3+……+an)*(n-1)!+2*(∑|ai-aj|(i!=j))*(n-1)!]/(n!)
=[a1+a2+a3+……+an+2*(∑|ai-aj|(i!=j))]/n
接下来:我们就要考虑计算∑|ai-aj|(i!=j)的问题。
其实,这个就相当于,给定n个点,求所有ai-aj的和。
4,再举一个例子:
L1=a2-a1 L2=a3-a2 L3=a4-a3
我们记T3为黄色的路线,T2为红色……。T则为∑|ai-aj|(i!=j)。
那么,T=T3+T2+T1
=(3L3+2L2+1L1)+(2L2+1L1)+(1L1)
=(1L1)+ (1L1+2L2)+(1L1+2L2+3L3)
很明显,T(i)=T(i-1)+i*Li
那么:可以用变量S把Ti计算出来,再用num把S累加就可以了(注意要乘二)。
如果按照上面的算法,则时间复杂度为O(n)。
5,
Ans = [(a1+a2+a3+……+an)+num]/n
则比为
(a1+a2+a3+……+an)+num:n
最后再用gcd它们的求最大公约数就可以了(记得用longlong)。
【程序】
#include这是一数学题,很值得思考。#include #include #include using namespace std;const int MAXN=100007;int n;int dis[MAXN];long long sum,ans,s;long long gcd(long long x,long long y){ if(!(x%y)) return y; return gcd(y,x%y);}int main(){ scanf("%d",&n); for(int i=1;i<=n;++i) { scanf("%d",&dis[i]); sum+=dis[i]; } sort(dis+1,dis+n+1); dis[0]=0; for(int i=1;i