CF1445D. Divide and Sum 组合数

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

题意:

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

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

题解:

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

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

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

代码:

#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
",timess,8ll*rev(8ll)%MOD);
    ans=(ans*timess)%MOD;
    printf("%lld
",ans);

    return 0;
}
原文地址:https://www.cnblogs.com/isakovsky/p/13964303.html