题目链接:
https://codeforces.com/problemset/problem/1444/B
题目大意:
给你一个长度为 2 * n 的数列, 你要选取其中n个数,将选择的数组成p数列
剩下的数组成q数列,并且使得p按照不下降顺序排列,q按照不上升顺序排列
现在对于某一种选法,设f(p,q)为 i 从 1到n 每个位置 的abs(qi - pi) 之和
现在求所有选择方法f(p,q)之和,答案对998244353 取模
输入与输出:
input:
第一行一个n代表有2*n个数字
第二行2n个数字,代表初始数列
output:
一个数字代表答案
思路:
1.
对于某一种选择方法,我们要求每个位置的abs(qi - pi)
abs不利于整体维护,我们可以设法消除,
我们设xi = abs(qi - pi)
那么 如果 qi < pi 我们就让qi和pi交换一下
也就是说xi = max(qi, pi) - min(qi, pi)
我们设max(qi, pi) 这么i个数字组成的数列为a
设min(qi, pi) 这么i个数字组成的数列为b
那么对于某一种选择方法,f(p,q) = sum(a) - sum(b)
2.
由于p为单调递增的
且q为单调递减的
可以证明:a 始终为原始较大的n个数
b 始终为原始较小的n个数
如果p,q中一个数列始终大于另一个,结论非常好得
如果 存在i使得 pi < qi,p(i+1) >= q(i+1)
那么易得min(a) = min(qi, p(i+1))
max(b) = max(pi, q(i+1))
而且 pi <= qi && pi <= p(i+1)
q(i+1) <= p(i+1) && q(i+1) <= qi
故min(a) >= max(b)
故a为原数列较大的n个数
如图:
(黄p,绿q,红a,蓝b)
而要是p,q不是一增一减则不满足
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 3e5 + 5;
const int mod = 998244353;
typedef long long LL;
int n, xx[maxn];
int sm1, sm2, dsm, res;
void read()
{
scanf("%d", &n);
for (int i = 1; i <= 2 * n; i++)
scanf("%d", xx + i);
}
int qpow(LL xx, LL yy)
{
int ret = 1;
while (yy) {
if (yy & 1) {
ret = (LL)ret * xx % mod;
}
xx = xx * xx % mod;
yy >>= 1;
}
return ret;
}
int getnm()
{
int ret = 1;
int div = 1;
for (int i = 2 * n; i >= n + 1; i--) {
ret = (LL)ret * i % mod;
}
for (int i = 1; i <= n; i++)
div = (LL)div * i % mod;
ret = (LL)ret * qpow(div, mod - 2) % mod;
return ret;
}
void deal()
{
sort(xx + 1, xx + 1 + 2 * n);
for (int i = 1; i <= n; i++)
sm1 = ((LL)sm1 + xx[i]) % mod;
for (int i = 2 * n; i >= n + 1; i--)
sm2 = ((LL)sm2 + xx[i]) % mod;
dsm = (sm2 - sm1 + mod) % mod;
res = (LL)dsm * getnm() % mod;
printf("%d\n", res);
}
int main()
{
read();
deal();
return 0;
}