题意
给出一个长为n的序列,对于这个序列的任意一个排列,求∑fa\sum f_a∑fa的值。
题解
我们枚举每一个aia_iai然后,计算aia_iai出现了多少次,然后把ai∗numa_i*numai∗num加入到ans里面。
考虑aia_iai什么时候出现。
aia_iai出现的位置前面的aja_jaj必须严格小于aia_iai,这样aia_iai才能被取到,而且aia_iai后面一定要有比它大的数,这样才能aia_iai取到。
假设小于aia_iai的数有mmm个,那么numm=∑r=0mCmr∗r!∗(n−1−r)!num_m = \sum_{r = 0}^mC_m^r*r!*(n-1-r)!numm=∑r=0mCmr∗r!∗(n−1−r)!
整个的公式就是:
∑i=1nai∗numi\sum_{i = 1}^na_i*num_i∑i=1nai∗numi
但这样暴力求的话时间复杂度是O(n2)O(n^2)O(n2),因此必须运用公式变换上述式子,可以证明numinum_inumi可以在O(1)O(1)O(1)的时间求出来,具体求解方法见下图。
题解
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
#define pr(x) cout<<#x<<":"<<x<<endl
const int maxn = 1e6+10;
typedef long long ll;
const ll mod = 1e9+7;
ll a[maxn],fac1[maxn],fac2[maxn];
int n;
int main(){scanf("%d",&n);for(int i = 0;i < n;++i)scanf("%lld",&a[i]);sort(a,a+n);fac1[0] = 1;fac2[n+1] = 1;fac2[n] = n;for(int i = 1;i <= n;++i)fac1[i] = fac1[i-1]*i%mod;for(int i = n-1;i >= 1;--i)fac2[i] = fac2[i+1]*i%mod;ll ans = 0;for(int i = 0,j = 1;i < n && a[i] != a[n-1];i = j){for(j = i;a[i] == a[j];j++);ll num = j-i;ans = (ans + num*((a[i]*fac1[n-i-1]%mod)*fac2[n-i+1]))%mod;}cout<<ans<<endl;return 0;
}