Codeforce 1445D Divide and Sum

本文针对Codeforce1445D问题提供了解决方案,通过对数组进行特定操作来计算所有可能的分解方法的和,并通过快速幂与逆元的方法高效计算组合数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Codeforce 1445D Divide and Sum

链接

http://codeforces.com/contest/1445/problem/D

题目大意

(更的有点晚。。。)
给你一个2n长度的数组,把它任意分解成两个长度为n的数组p,q。
我们令
在这里插入图片描述
求所有分解方法的f(p,q)的和对998244353取模。

输入输出

input:
1
1 4
output:
6

input:
2
2 1 2 1
output:
12

input:
3
2 2 2 2 2 2
output:
0

input:
5
13 8 35 94 9284 34 54 69 123 846
output:
2588544

数据范围

1<=n<=150000
1<=ai<=1e9

说明

对于样例2,
1 2 1 2 这4个数显然有C(4,2) = 6 种分解方法:
【2,1】【2,1】 ,f = 2
【1,1】【2,2】, f = 2
【2,1】【1,2】, f = 2
【1,2】【2,1】, f = 2
【1,1】【2,2】, f = 2
【2,1】【2,1】, f = 2
2+2+2+2+2+2 = 12;

思路

我们很容易发现,对于每一种分解方法,f(p,q)的结果都是
让数组中大的一半减去小的一半。
可以这样简单地证明一下:
我们先令a2n 有序:
则f(p,q) = a2n+a2n-1+a2n-2+…+an+1 - an-an-1-…-a1 @

令集合A = {a2n,a2n-1,a2n-2,…,an+1},即大的半边
集合B = {an,an-1,…,a1} 即小的半边,则f(p,q) = sumA-sumB;

现在我们对@式进行一些变形:
1.我们令B集合中的ai与A集合中的ai+n互换。
例如我们把a2n-an 换成 an-a2n.那么因为加了绝对值,显然总和是不变的
2.那么如果我们把B集合中的ai与A集合中的aj+n互换呢?
我们发现,原式 = |ai+n-ai| + |aj+n-aj| = |aj+n-ai|+|ai+n-aj| =ai+n+aj+n- ai-aj.
所以,得出结论:我们任意地将B集合中的元素换到A中,得到的f(p,q)始终等于sumA-sumB。

到这里本题就变得很简单了:
1.对a2n排序
2.sum(大的半边)- sum(小的半边)
3.求组合数C(2n,n)
求组合数时注意由于需要大数据取模,应该采用快速幂+逆元的做法。(记得取模)

代码

  #include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll maxn  = 150005;
const ll p = 998244353; 
ll fac[2*maxn+5];
ll a[maxn*2+10];
 ll quick_pow(ll x, ll n, ll mod){
    ll res = 1;
    while (n!=0){
            if (n & 1){
                res = res * x % mod;
            }    
         	x = x * x % mod;
            n >>= 1;
        }
        return res;
}
ll solve(ll n,ll m){
    fac[0] = 1;
        for (int i = 1; i <= n; i++){
            fac[i] = fac[i - 1] * i % p;
            }
        return fac[n] * quick_pow(fac[m], p - 2, p) % p * quick_pow(fac[n - m], p - 2, p) % p;
}
         
         
int main()
{
    int n;
    cin>>n;
    for(int i=0;i<2*n;i++){
    	scanf("%lld",&a[i]);
    }
        sort(a,a+2*n);
        ll ans = 0;
        for(int i=0;i<n;i++){
        	ans  = (ans + a[i+n] - a[i]) % p;
    }
        cout<<ans*solve(2*n,n)%p<<endl;
        return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值