魔法排列
题目
众所周知,集合 {1 2 3 … N} 有 N! 种不同的排列,假设第 i 个排列为 Pi 且 P[i][j] 是该排列的第 j 个数。
将 N 个点放置在 x 轴上,第 i 个点的坐标为 xi 且所有点的坐标两两不同。
对于每个排列(以 Pi 为例),可以将其视为对上述 N 个点的一种遍历顺序,即从第 P[i][1] 个点出发,沿直线距离到达第 P[i][2] 个点,再沿直线距离到达第 P[i][3] 个点,以此类推,最后到达第 P[i][N] 个点,将该路线的总长度定义为 L(Pi),那么所有 N! 种路线的总长度之和是多少,即 L(P1) + L(P2) + L(P3) + ... + L(PN!) 的结果是多少?
输入描述
第一行包含一个整数 N,1 ≤ N ≤ 10^5。
第二行包含 N 个空格隔开的整数 x1 到 xN,0 ≤ x1 < x2 < x3 < ... < xN ≤ 10^9。
输出描述
输出 L(P1) + L(P2) + L(P3) + ... + L(PN!) 对 10^9 + 7 取模后的结果。
样例输入
3
0 1 3
样例输出
24
说明
P1={1 2 3},P2={1 3 2},P3={2 1 3},P4={2 3 1},P5={3 1 2},P6={3 2 1};
L(P1)=3,L(P2)=5,L(P3)=4,L(P4)=5,L(P5)=4,L(P6)=3。
AC 代码
import java.util.Scanner;
/**
* 思路:这道题的主要思路是排列组合
*
* 例如有4个数[1, 2, 3, 4],那么所有的排列组合为:
* 1 2 3 4 --- 1 2 4 3 --- 1 3 2 4 --- 1 3 4 2 --- 1 4 2 3 --- 1 4 3 2
* 2 1 3 4 --- 2 1 4 3 --- 2 3 1 4 --- 2 3 4 1 --- 2 4 1 3 --- 2 4 3 1
* 3 1 2 4 --- 3 1 4 2 --- 3 2 1 4 --- 3 2 4 1 --- 3 4 1 2 --- 3 4 2 1
* 4 1 2 3 --- 4 1 3 2 --- 4 2 1 3 --- 4 2 3 1 --- 4 3 1 2 --- 4 3 2 1
*
* 可以发现,任意连个数相邻的情况都为 6,例如有 6 个 1 2
* 这个 6 是怎么来的呢?可以把 1 2 捆绑在一起,那么就变成了如何将 1 2 3 4 放在三个坑中
* 得到 A(3, 3) = 6 种
*
* 其他的方式也一样,另外 1 2 和 2 1 是两种不同的组合,在计算时只需要乘以 2 即可
*/
public class Test {
public static long mod = 1000000007;
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int N = scanner.nextInt();
int[] x = new int[N];
for (int i = 0; i < N; i++) {
x[i] = scanner.nextInt();
}
int n = factorial(x.length - 1);
/**
* 时间复杂度 O(N)
*
* 思想:
* 例如 1 2 3 4 要计算 len(1, 4) + len(2, 4) + len(3, 4)
* = (4 - 1) + (4 - 2) + (4 - 3)
* = 4 * 3 - (1 + 2 + 3)
*/
long sum = 0, tem = 0, a;
for (int i = 1; i < x.length; i++) {
tem = (tem + x[i - 1]) % mod;
// 这里不能直接写成 a = x[i] * i;
// 因为 a 的类型为 long,而 x[i] 和 i 都是 int 类型
// 两个 int 类型的数相乘就有导致溢出
a = x[i] * (long)i;
sum = (sum + a - tem) % mod;
}
sum = (sum << 1) % mod;
sum = (sum * n) % mod;
System.out.println(sum);
}
// 计算 N!
public static int factorial (int n) {
long result = 1;
for (int i = 1; i <= n; i++) {
/**
* 这里可以这样计算的原因是
* (a * b) % c = ((a % c) * (b % c)) % c
*/
result = (result * i) % mod;
}
return (int) result;
}
}