CF1444B(CF1445D) Divide and Sum

一个水题,但是考场上愣是想了一个小时,最后忘了加模数再取模导致我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;
}
原文地址:https://www.cnblogs.com/Gensokyo-Alice/p/13911997.html