1. 程式人生 > 實用技巧 >CF1445D Divide and Sum

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}^{2\cdot 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\n", (ans + MOD) % MOD);
    return 0;
}