发现有一种奇怪的方法不能快速预处理?
复习一下常见的凑组合数的套路
You are given an array a of length n. We define fa the following way:
- Initially fa = 0, M = 1;
- for every 2 ≤ i ≤ n if aM < ai then we set fa = fa + aM and then set M = i.
Calculate the sum of fa over all n! permutations of the array a modulo 109 + 7.
Note: two elements are considered different if their indices differ, so for every array a there are exactly n! permutations.
Input
The first line contains integer n (1 ≤ n ≤ 1 000 000) — the size of array a.
Second line contains n integers a1, a2, ..., an (1 ≤ ai ≤ 109).
Output
Print the only integer, the sum of fa over all n! permutations of the array a modulo 109 + 7.
题目大意
题目分析
主要是记一下一种凑组合数的常见套路,网上其他人都是一种另外的考虑方式。
对于数$a_q$枚举它每一个出现位置的贡献,记严格小于它的数有$m$个,则有$a_qsumlimits_{p=1}^n{m choose {p-1}}(p-1)! (n-p)!$即$a_q m!sumlimits_{p=1}^n{{(n-p)!}over {(m-p+1)!}}$。于是就会发现右边这个东西分子分母都有自变量,看上去很难处理,但形式上又是有些相似的感觉。
式子可以接着这么化:$a_qm!(n-m+1)!sumlimits_{p=1}^n{{n-p}choose{n-m-1}}$,也就是把右式做成一个组合数。
注意到新的右式是经典问题组合数的列前缀和,于是化成:$a_qm!(n-m+1)!{{n}choose{n-m}}$
最后化简得到:$a_qn!over{n-m}$
1 #include<bits/stdc++.h> 2 #define MO 1000000007 3 const int maxn = 1000035; 4 5 int n,ans,cnt,a[maxn],fac[maxn],inv[maxn]; 6 7 int read() 8 { 9 char ch = getchar(); 10 int num = 0, fl = 1; 11 for (; !isdigit(ch); ch=getchar()) 12 if (ch=='-') fl = -1; 13 for (; isdigit(ch); ch=getchar()) 14 num = (num<<1)+(num<<3)+ch-48; 15 return num*fl; 16 } 17 int main() 18 { 19 n = read(); 20 for (int i=1; i<=n; i++) a[i] = read(); 21 std::sort(a+1, a+n+1); 22 fac[0] = fac[1] = inv[0] = inv[1] = 1; 23 for (int i=2; i<=n+2; i++) 24 inv[i] = MO-1ll*(MO/i)*inv[MO%i]%MO, 25 fac[i] = 1ll*fac[i-1]*i%MO; 26 for (int i=1,j; i<=n; i=j+1) 27 { 28 for (j=i; a[j+1]==a[i]; j++); 29 if (j==n) break; 30 cnt = inv[n-i+1]; 31 ans = (1ll*ans+1ll*a[i]*(j-i+1)%MO*cnt%MO)%MO; 32 } 33 printf("%d ",1ll*ans*fac[n]%MO); 34 return 0; 35 }
END