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