Codeforces Round #680B

Codeforces Round #680B

大意

给定长度为\(2n\)的正整数序列,将其分为两个长度相同子列\(a,b\),将\(a\)中元素降序排列\(b\)中升序排列。

求对于所有的排序后的\(a_k,b_k\),\(\Sigma_k\Sigma_i(|a_{ki}-b_{ki}|)\)的值。

思路

最重要的一点,每一种分划方式得到的\(a_k,b_k\)\(\Sigma_i(|a_{ki}-b_{ki}|)\)的值一定相等。

最后答案就是\(\begin{pmatrix} 2n \\ n \end{pmatrix} * \Sigma_i(|a_i-b_i|)\)

现证明每种分划的求和相等。

alt

考虑将划分中的值按其在排序中的位置放到坐标平面上并连接,意义已经标注在图上。

实际的点并不连续,也可能并不单调递减,但不影响思考。

考虑图中的情况。显然存在\(k\),满足\(a_k>b_k\)\(a_{k+1}\leq b_{k+1}\)

\(\therefore \forall i>k,|a_i-b_i| = b_i-a_i\)

\(a_i,b_i\)交换\((i>k)\),得到一组新的序列\(a',b'\) 。如下图。

alt

交换前后显然\(\Sigma_i(|a_i-b_i|)\)不变,但是\(\forall i,j\)\(a_i'\geq b_j'\)

所以得到\(\Sigma_i(|a_i-b_i|)=\Sigma_i(|a_i'-b_i'|)=c\)

\(c\)是原序列中前n大之和和前n小之和的差值。

当然,要A掉这题,你还要会逆元和组合数。

代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;

#define ll long long
#define ull unsigned long long
#define cint const int&
#define Pi acos(-1)
const int inf_int = 0x7fffffff;
const ll inf_ll = 0x7fffffffffffffff;
const double ept = 1e-9;
const int mod = 998244353;

int n;
int a[300200];

ll fac(int N) {
    ll ans = 1;
    for(ll i=2; i<=N; i++)
        ans = (ans*i)%mod;
    return ans;
}

ll ksm(ll x, int c) {
    ll ans = 1;
    ll tmp = x;
    while(c) {
        if(c&1) ans = (ans*tmp) % mod;
        c >>= 1;
        tmp = (tmp*tmp) % mod; 
    }
    return ans;
}

ll counter(int N) {
    return (fac(2*N)*ksm((fac(N)*fac(N))%mod, mod-2)) % mod;
}

int main() {
    cin >> n;
    for(int i=1; i<=2*n; i++) cin >> a[i];
    sort(a+1, a+1+2*n);
    ll pre = 0;
    for(int i=1; i<=n; i++)
        pre = (pre + a[n+i] - a[i]) % mod;
    cout << (pre*counter(n)) % mod;
    return 0;
}
posted @ 2020-11-08 18:42  ullio  阅读(95)  评论(0)    收藏  举报