前后缀+组合规律+线性求阶乘逆元
https://atcoder.jp/contests/abc151/tasks/abc151_e
题意:给你n个数,从中任意选出k个数作为一组,求出任意组合的最大值-最小值之和。
解法:排序,前缀和和后缀和,组合规律。
#include<stdio.h> #include<string.h> #include<math.h> #include<queue> #include<algorithm> #include<iostream> #include<map> #define inf 0x3f3f3f3f #define ll long long #define maxx 5000000 #define mod 1000000007 using namespace std; const int N = 100002; ll a[N] , sum1[N] , sum2[N] , fac[N] , inv[N]; ll quickpow(ll a, ll b) { ll ans = 1 ; while(b) { if(b&1) { ans = ans * a % mod ; } b >>= 1 ; a = a * a % mod ; } return ans%mod; } void init() { fac[0] = fac[1] = inv[0] = inv[1] = 1 ; for(int i = 2 ; i <= N-2 ; i++) fac[i] = fac[i-1] * i % mod; inv[N-2] = quickpow(fac[N-2] , mod-2); for(int i = N -3 ; i >= 2 ; i--) inv[i] = inv[i+1] * (i+1) % mod; } ll C(int n , int m) { return fac[n]%mod * inv[m]%mod * inv[n-m]%mod; } int main() { init(); ll n , k ; scanf("%lld%lld" , &n , &k); for(int i = 1 ; i <= n ; i++) { scanf("%lld" , &a[i]); } sort(a+1 , a+n+1); for(int i = 1 ; i <= n ; i++) { sum1[i] = sum1[i-1] + a[i]; } for(int i = n ; i >= 1 ; i--) { sum2[i] = sum2[i+1] + a[i]; } ll a = k - 2 , b = a , ans = 0; for(int i = n - k + 1 , j = k ; i >= 1 ; i-- , j++ , a++) { ans = (ans%mod + (sum2[j] - sum1[i])%mod * C(a , b))%mod; } cout << ans << endl ; return 0 ; }