CF1445D. Divide and Sum 组合数

传送门:https://codeforces.com/contest/1445/problem/D

题意:

一个数组,任意取出一半,从小到大排序放到数组a里,另一半从大到小排序放到数组b里,求两个数组对应位置之差的和

对于这个数组的任意分配方式,对于这个结果再求和

题解:

赛时暴力跑出来结论:这个数组不管怎么拆,对应位置差之和都是一样的

其实不难理解,这个数组中大的那一半对答案贡献一定是正的,负的那一半对答案贡献是负的。

因此,将这个数组随意分拆,分别sort之后求绝对值和,然后再用快速幂和Fermat小定理计算Cn2n,再相乘即可。

代码:

复制代码
#include<bits/stdc++.h>
#define MOD 998244353
#define LL long long
using namespace std;
int n;
int a[150005],b[150005],c[300005];
inline int iabs(int a) {
    return a>0?a:-a;
}
LL qpow(LL a,int n) {
    LL ans=1;
    LL base=a;
    while(n) {
        if(n&1)ans=(ans*base)%MOD;
        base=(base*base)%MOD;
        n>>=1;
    }
    return ans;
}
LL rev(LL a) {
    return qpow(a,MOD-2);
}
int main() {
    //while(1) {
    scanf("%d",&n);
    for(int i=1; i<=2*n; i++) {
        scanf("%d",&c[i]);
    }
    for(int i=1; i<=n; i++) {
        //printf("%d ",c[i]);
        a[i]=c[i];
        b[i]=c[i+n];
    }
    sort(a+1,a+1+n);
    sort(b+1,b+1+n,greater<int>());
    LL ans=0;
    for(int i=1; i<=n; i++) {
        ans+=iabs(a[i]-b[i]);
        ans%=MOD;
    }
    LL timess=1;
    for(int i=1; i<=n; i++) {
        timess=(timess*(i+n))%MOD;
        timess=(timess*rev(1LL*i))%MOD;
    }
//        sort(c+1,c+1+2*n);
//        do {
//
//
//
//
//        } while(next_permutation(c+1,c+1+2*n));
    //}
    //printf("debug %lld %lld\n",timess,8ll*rev(8ll)%MOD);
    ans=(ans*timess)%MOD;
    printf("%lld\n",ans);

    return 0;
}
复制代码

 

posted @   Isakovsky  阅读(158)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示