题目链接:戳这里
题目大意:
我们定义f(a)为:
1、开始时,f(a)=0,M=1。
2、对于每个2<=i<=n,如果a[M]<a[i],那么f(a)=f(a)+a[M],M=i。
现在对于一个给定的数组a,求其所有排列的f(a)之和,答案对1e9+7取模。
题解:
一开始以为是把f(a)变成a[M],然后不会做。
后来发现是题看错了QAQ。
既然是加上,那么我们可以分开统计每个数的贡献。
如果一个数要有贡献,那么在这个排列中,排在该数前的数都比该数小,排在该数后的都比该数大--->也就是顺序排列。
所以一个数的贡献次数为:
(图从别的博客扒的)
也就是从n个位置中找n-i+1个大于等于该数的位置,其中该数在第一个位置,前i-1个位置和后n-i的位置的数都任意排列的值。
化简一下是n!/(n-i+1)。
那么一个数的贡献就是贡献次数*这个数*出现次数。
加起来即可,除法可以用逆元解决。
代码:
#include<bits/stdc++.h>
#define mod 1000000007
#define maxn 1000005
using namespace std;
typedef long long LL;
int read()
{
char c;int sum=0,f=1;c=getchar();
while(c<'0' || c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0' && c<='9'){sum=sum*10+c-'0';c=getchar();}
return sum*f;
}
int n;
int a[maxn];
LL ksm(LL a,LL b)
{
LL ret=1;
while(b)
{
if(b&1) ret=ret*a%mod;
a=a*a%mod;
b>>=1;
}
return ret;
}
LL A=1,ans;
int main()
{
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),A=A*i%mod;
sort(a+1,a+1+n);
int pos;
for(int i=1;i<=n;i=pos)
{
pos=i;
while(a[i]==a[pos] && pos<=n) pos++;
if(pos<=n)
ans=(ans+A*ksm(n-i+1,mod-2)%mod*(pos-i)%mod*a[i]%mod)%mod;
}
cout<<ans<<endl;
return 0;
}