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|)\)。
现证明每种分划的求和相等。
考虑将划分中的值按其在排序中的位置放到坐标平面上并连接,意义已经标注在图上。
实际的点并不连续,也可能并不单调递减,但不影响思考。
考虑图中的情况。显然存在\(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'\) 。如下图。
交换前后显然\(\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;
}

浙公网安备 33010602011771号