题目链接
题目大意
给你n个数字,求所有排列的fa的和:对于一个排列来说,一开始fa为1,m=1,若a[m]<a[i] fa=fa+a[m]。m=i
概率
看到这个方法觉得很神奇,但又确实高中的时候一些组合数学的题目的确可以用概率的方法来解。而且简单很多。首先sort一下,然后计算大于等于a[i]的个数x(包括自己),如果要保证a[i]被算进贡献,那么就必须在这个排列中,所有大于等于a[i]的个数中,a[i]在序列最前端,即第一个位置,显然概率就是1/x,然后有n!种方案。然后就可以求出答案
组合数学
第二种方法就有点难了。要涉及许多组合数学的问题。设有rk[i]个比a[i]小的数,显然这些数可以放在a[i]前面,而大于等于a[i]的数要放在a[i]后面。那么a[i]的贡献显然为
∑
j
=
0
r
k
[
i
]
A
r
k
[
i
]
j
∗
(
n
−
j
−
1
)
!
\sum_{j=0}^{rk[i]}A_{rk[i]}^{j}*(n-j-1)!
∑j=0rk[i]Ark[i]j∗(n−j−1)!化简为
r
k
[
i
]
!
∗
∑
j
=
0
r
k
[
i
]
(
n
−
j
−
1
)
!
(
r
k
[
i
]
−
j
)
!
rk[i]!*\sum_{j=0}^{rk[i]}\frac{(n-j-1)!}{(rk[i]-j)!}
rk[i]!∗∑j=0rk[i](rk[i]−j)!(n−j−1)!而如果这么计算的话那么复杂度是线性的,再加上有n个a[i]那么复杂度就是
O
(
n
2
)
O(n^2)
O(n2),显然过不了,那么还要化简,首先你要明白一个公式
C
k
k
+
C
k
+
1
k
+
.
.
.
.
.
+
C
n
k
=
C
n
+
1
k
+
1
C_{k}^{k}+C_{k+1}^{k}+.....+C_{n}^{k}=C_{n+1}^{k+1}
Ckk+Ck+1k+.....+Cnk=Cn+1k+1
一直好奇这个式子怎么来的。。其实很简单就是一直运用pasacl公式
C
n
+
1
k
+
1
=
C
n
k
+
C
n
k
+
1
=
C
n
k
+
C
n
−
1
k
+
C
n
−
1
k
+
1
=
.
.
.
.
.
.
.
=
C
n
k
+
C
n
−
1
k
+
.
.
.
.
C
k
k
C_{n+1}^{k+1}=C_{n}^{k}+C_{n}^{k+1}=C_{n}^{k}+C_{n-1}^{k}+C_{n-1}^{k+1}=.......=C_{n}^{k}+C_{n-1}^{k}+....C_{k}^{k}
Cn+1k+1=Cnk+Cnk+1=Cnk+Cn−1k+Cn−1k+1=.......=Cnk+Cn−1k+....Ckk
然后根据这个公式再度化简让分子分母同时乘以(n-rk[i]-1)!结果就变成
(
n
−
r
k
[
i
]
−
1
)
!
∗
r
k
[
i
]
!
∗
∑
j
=
0
r
k
[
i
]
(
n
−
j
−
1
)
!
(
r
k
[
i
]
−
j
)
!
∗
(
n
−
r
k
[
i
]
−
1
)
!
(n-rk[i]-1)!*rk[i]!*\sum_{j=0}^{rk[i]}\frac{(n-j-1)!}{(rk[i]-j)!*(n-rk[i]-1)!}
(n−rk[i]−1)!∗rk[i]!∗∑j=0rk[i](rk[i]−j)!∗(n−rk[i]−1)!(n−j−1)!再度化简变成
(
n
−
r
k
[
i
]
−
1
)
!
∗
r
k
[
i
]
!
∗
∑
j
=
0
r
k
[
i
]
C
n
−
j
−
1
n
−
r
k
[
i
]
−
1
=
(
n
−
r
k
[
i
]
−
1
)
!
∗
r
k
[
i
]
!
∗
C
n
n
−
r
k
[
i
]
=
n
!
n
−
r
k
[
i
]
(n-rk[i]-1)!*rk[i]!*\sum_{j=0}^{rk[i]}C_{n-j-1}^{n-rk[i]-1}=(n-rk[i]-1)!*rk[i]!*C_{n}^{n-rk[i]}=\frac{n!}{n-rk[i]}
(n−rk[i]−1)!∗rk[i]!∗∑j=0rk[i]Cn−j−1n−rk[i]−1=(n−rk[i]−1)!∗rk[i]!∗Cnn−rk[i]=n−rk[i]n!
然后答案就变成了
∑
i
=
1
i
=
n
a
[
i
]
∗
n
!
n
−
r
k
[
i
]
\sum_{i=1}^{i=n}a[i]*\frac{n!}{n-rk[i]}
∑i=1i=na[i]∗n−rk[i]n!
两个方法显然推出来的式子一样
代码
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fi first
#define se second
#define debug printf("I am here\n");
using namespace std;
typedef long long ll;
const int maxn=1e6+5,mod=1e9+7,inf=0x3f3f3f3f;
const double eps=1e-10;
int n,t,a[maxn],rk[maxn];
ll fac[maxn];
ll qpow(ll a,ll b){
ll ans=1,base=a;
while(b){
if(b%2){
ans=ans*base%mod;
}
base=base*base%mod;
b=b>>1;
}
return ans;
}
void init(){
fac[0]=1;
for(int i=1;i<=1e6;i++){
fac[i]=fac[i-1]*i%mod;
}
}
int main(){
init();
scanf("%d",&n);i
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
sort(a+1,a+1+n);
//rk[i]表示小于排序后的a[i]的个数
for(int i=1;i<=n;i++){
if(a[i]>a[i-1]){
rk[i]=i-1;
}else{//表示相等
rk[i]=rk[i-1];
}
}
ll sum=0;
for(int i=1;i<=n;i++){
if(rk[i]==rk[n]) break;//当a[i]等于最大显然要break,因为大于a[i]的个数为0个
sum=(sum+1ll*a[i]*fac[n]%mod*qpow(n-rk[i],mod-2)%mod)%mod;
}
printf("%lld\n",sum);
return 0;
}