题解:CF938E Max History

· · 题解

根据题意,当一个点前面全比它小,后面有比它大的,它就能做出一个贡献。 那对于一个点,我们二分出有多少个点是大于等于它的(包含其本身),设这个数量为 $x$,那这个点做出的贡献就是这 $x$ 个点在满足当前点在最前面的情况下的摆放方式之和。 那就可以直接列出式子了。设第 $i$ 个点做出了 $f_i$ 次贡献。 $$f_i = \binom{n}{x} \times (x-1)! \times (n-x)!$$ 上面的第二项之所以是 $(x-1)!$ 而不是 $x!$ 是因为当前点已经固定在最前面了。 $$Ans = \sum^{n}_{i=1} f_i \times a_i$$ 注意最大值的 $f_i = 0$。 复杂度是 $O(n \log n)$ 的,过了。 ```cpp /****************************** - @GavinCQTD - "E. Max History" - # https://codeforces.com/problemset/problem/938/E - 3000 ms ******************************/ #include <algorithm> #include <iostream> #include <cassert> using namespace std; using ll = long long; using ull = unsigned long long; using ld = long double; constexpr int MOD=1e9+7; int n,a[1000005],b[1000005],x[1000005],mx=0; ull fac[1000005]; ull qpow(ull a,ull b,ull P){ ull res=1; while(b!=0){ if(b&1){ res = res*a%P; } a = a*a%P; b >>= 1; } return res; } ull inv(ull x,ull P){ return qpow(x,P-2,P); } ull C(ull a,ull b){ return (fac[a]*inv(fac[a-b],MOD)%MOD)*inv(fac[b],MOD)%MOD; } int main(){ cin >> n; for(int i=1;i<=n;i++){ cin >> a[i]; b[i] = a[i]; mx = max(mx,a[i]); } sort(b+1,b+n+1); fac[0] = 1; for(int i=1;i<=n;i++){ fac[i] = fac[i-1]*i%MOD; } for(int i=1;i<=n;i++){ int l=1,r=n,rk=0; while(l<=r){ int mid=(l+r)>>1; if(b[mid]<a[i]){ rk = mid; l = mid+1; } else{ r = mid-1; } } x[i] = n-rk; } ull ans=0; for(int i=1;i<=n;i++){ if(a[i]==mx){ continue; } ans += ((fac[x[i]-1]*fac[n-x[i]]%MOD)*C(n,x[i])%MOD)*a[i]%MOD; ans %= MOD; } cout << ans << "\n"; return 0; } ```