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