CF938E Max History(组合数学)
这题目最原始的想法我们先对序列排序,发现每个数的贡献其实就是先找到比他小的数的个数记为cnt
然后枚举这个数所在的位置,之后就可以从cnt中选j-1个填到前面,然后还要进行排列
但是这样超过了复杂度,所以我们考虑优化这个组合数表达式,首先是简单的约分
约后,我们发现上下两个阶乘中间的数相减就是一个常数,如果遇到这种情况,可以在外面乘上这个常数的阶乘,然后求和里面除掉。就能把求和变成一个组合数
根据杨辉三角变化,就能变成一个可以直接计算的答案了
#include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #include<map> #include<string> #include<vector> using namespace std; typedef long long ll; const int N=1e6+10; const ll mod=1e9+7; ll a[N]; ll qmi(ll a,ll b,ll mod){ ll res=1; while(b){ if(b&1) res=(res*a)%mod; a=a*a%mod; b>>=1; } return res%mod; } int main(){ ll n; cin>>n; ll tot=1; int i; for(i=1;i<=n;i++) tot=tot*i%mod; for(i=1;i<=n;i++){ scanf("%lld",&a[i]); } sort(a+1,a+1+n); ll ans=0; int j; for(i=1;i<=n;i=j){ for(j=i;a[j]==a[i];j++); if(j<=n) ans=(ans+tot*qmi(n-i+1,mod-2,mod)%mod*(j-i)%mod*a[i])%mod; } cout<<ans<<endl; return 0; }
没有人不辛苦,只有人不喊疼