codeforces1444B Divide and Sum #680 (Div. 1, based on Moscow Team Olympiad)

题目链接:

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;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值