CF938E Max History 组合计数

套路:对于这种计算所有情况价值和的问题计算每一个点对答案的贡献.

我们发现,位置 $i$ 能对答案贡献 $val[i]$,当且仅当 $i$ 是前缀最大值,且 $i$ 不等于序列中最大元素.

我们不妨考虑哪些点大于等于 $val[i]$ 的位置,那么 $val[i]$ 能产生贡献的话显然要求 $i$ 在这些位置中排在最靠前.

这样的话组合就好列了:$\binom{n}{n-num}\times num!\times (n-num-1)!$

 code:

#include <cstdio> 
#include <algorithm>  
#define N 1000007 
#define ll long long 
#define mod 1000000007  
#define setIO(s) freopen(s".in","r",stdin) 
using namespace std;      
int inv[N],fac[N],A[N],val[N],mn[N],n;  
int qpow(int x,int y) 
{
    int tmp=1; 
    for(;y;y>>=1,x=(ll)x*x%mod) 
        if(y&1) tmp=(ll)tmp*x%mod; 
    return tmp; 
}      
int C(int x,int y) { return (ll)fac[x]*inv[y]%mod*inv[x-y]%mod; }  
int main() 
{ 
    // setIO("input"); 
    int i,j,ans=0;  
    scanf("%d",&n),inv[0]=fac[0]=1;   
    for(i=1;i<=n;++i) fac[i]=(ll)fac[i-1]*i%mod,inv[i]=qpow(fac[i],mod-2); 
    for(i=1;i<=n;++i) scanf("%d",&val[i]),A[i]=val[i];      
    sort(A+1,A+1+n);    
    for(i=1;i<=n;++i) mn[i]=lower_bound(A+1,A+1+n,val[i])-A-1;               
    for(i=1;i<=n;++i) 
    {    
        if(val[i]==A[n]) continue;   
        int tmp=(ll)C(n,n-mn[i])*fac[mn[i]]%mod*fac[n-mn[i]-1]%mod;           
        ans=(ll)(ans+(ll)tmp*val[i]%mod)%mod;  
    }    
    printf("%d\n",ans);  
    return 0;
}

  

posted @ 2020-01-10 15:34  EM-LGH  阅读(185)  评论(0编辑  收藏  举报