牛客周赛 Round 84(选讲
F/G
题意很明确让我们计算所有排列的陡峭值得期望
对于一个排列,它对答案的贡献是\(\frac{\sum_{i=1}^{n-1}|a_i-a_{i+1}|}{n!}\)
如果这时顺着题目的思路,找出每一个排列,然后计算每一个排列对答案的贡献,必然超时,时间复杂度达到了\(O(n!n)\)
所以我们需要考虑,是否有其他得计算方式
-
我们尝试将一个排列的贡献拆分得到\(\frac{|a_1-a_{2}|}{n!},......,\frac{|a_i-a_{i+1}|}{n!},.........,\frac{|a_{n-1}-a_{n}|}{n!}\)
这时候,我们的思路就打开,不必拘泥于对答案的贡献在一个数组内,而只要满足\(\frac{|a_i-a_{i+1}|}{n!}\)的形式皆可
-
我们固定\(a_i\)为\(x\),那么\(y\)是数组内任意不等于\(x\)的数,对于任意一个y,其他的数会有\((n-2)!\)个排列,于是乎这样一对\((x,y)\),对答案的贡献
\(\frac{|x-y|*(n-2)!}{n!}\),注意此时x的位置是固定的,所以\(a_i\)的位置可以n-1个,所以真正对答案的贡献\(\frac{|x-y|*(n-1)!}{n!}=\frac{|x-y|}{n}\)
固定一个x后用前后缀和计算所有的数对即可
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=2e5+10;
const int mod=1e9+7;
int n;
int a[maxn];
ll lsm(ll a,ll b){
ll cnt=1;
while(b){
if(b&1) cnt=cnt*a%mod;
a=a*a%mod;
b>>=1;
}
return cnt;
}
ll pre[maxn],nex[maxn];
int main(){
cin>>n;
for(int i=1;i<=n;++i) cin>>a[i];
sort(a+1,a+1+n);
for(int i=1;i<=n;++i) pre[i]=pre[i-1]+a[i];
for(int i=n;i>=1;--i) nex[i]=nex[i+1]+a[i];
ll ans=0;
for(int i=1;i<=n;++i)
ans=(ans+(nex[i+1]-(n-i)*a[i]+(i-1)*a[i]-pre[i-1])+mod)%mod;
cout<<ans*lsm(n,mod-2)%mod<<endl;
return 0;
}

浙公网安备 33010602011771号