一个水题,但是考场上愣是想了一个小时,最后忘了加模数再取模导致我fst。
考虑 (mid x_i - y_i mid) 的意义,就是 (max(x_i, y_i) - min(x_i, y_i)) 那么就是说对于每个位置,取两个排列中的最大值减去最小值。
这样的排列一共会有 (C_{2n}^n) 个。
这里先给出一个结论,排序后,后半部分永远会被取成最大值,前半部分永远会被取成最小值。
(以下内容均以排序后的原数组为准)
上述结论是由其排列排列顺序决定的,考虑后半部分的数如果放到 (p) 中,那么一定在最后几个。如果放到 (q) 中,一定在前几个,那么我们可以知道原序列的一半恰好等于 (p, q) 的长度,那么其实这些元素是不会相互之见取最大最小值的。
所以答案即为排序后的数组 (displaystyle Big( sum_{i=n+1}^{2cdot n} a_i - sum_{i=1}^n a_i Big) cdot C_{2n}^n)。
我比较菜,写的线性求逆元+阶乘。
时间复杂度 (O(n)),空间复杂度 (O(n))。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const ll MAXN = 1e6+10, MOD = 998244353;
ll N, M, fac[MAXN], val[MAXN], inv[MAXN], ans;
int main() {
scanf("%lld", &N);
inv[1] = inv[0] = fac[1] = fac[0] = 1;
for (ll i = 2; i <= N<<1; i++) fac[i] = fac[i-1] * i % MOD, inv[i] = inv[MOD % i] * (MOD - MOD / i) % MOD;
for (ll i = 1; i <= N<<1; i++) inv[i] = inv[i-1] * inv[i] % MOD;
for (ll i = 1; i <= N<<1; i++)
scanf("%lld", val+i);
ll tem = fac[N<<1] * inv[N] % MOD * inv[N] % MOD;
sort(val+1, val+(N<<1)+1);
for (ll i = 1; i <= N; i++)
ans = (ans - tem * val[i] % MOD) % MOD;
for (ll i = N + 1, k = N << 1; i <= k; i++)
ans = (ans + tem * val[i] % MOD) % MOD;
printf("%lld
", (ans + MOD) % MOD);
return 0;
}