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;
}
View Code

 

posted @ 2020-04-18 19:31  朝暮不思  阅读(193)  评论(0编辑  收藏  举报