[题解] [CF938E] Max History

题面

题解

考虑计算每一个数的贡献

我们设严格小于第 (i) 个数的数共有 (m_i)

只要这个数前面的数都比他小并且后面有比他大的数他的贡献就能算进去

那么对于这个数 (i) 的贡献就是

[displaystyle a_i(n-m_i-1)!(m_i)!inom{n}{n-m_i} ]

代表我们随意拜访比 (i) 大的数, 保证放在 (i) 后面即可

然后把这些数加上 (i) 自己插入 (n) 个位置中, 剩下的位置放这 (m_i) 个数

然后这 (m_i) 个数也可以自由排列, 对答案没有影响

所有的数的贡献加起来就行

最大值无法贡献

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
const int N = 1000005;
const int mod = 1000000007; 
using namespace std;

int n, a[N], m[N], cnt, last, fac[N], inv[N], ans; 

template < typename T >
inline T read()
{
	T x = 0, w = 1; char c = getchar();
	while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
	while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
	return x * w; 
}

int C(int n, int m)
{
	return 1ll * fac[n] * inv[n - m] % mod * inv[m] % mod; 
}

int fpow(int x, int y)
{
	int res = 1;
	for( ; y; y >>= 1, x = 1ll * x * x % mod)
		if(y & 1) res = 1ll * res * x % mod;
	return res; 
}

int main()
{
	n = read <int> ();
	for(int i = 1; i <= n; i++)
		a[i] = read <int> ();
	sort(a + 1, a + n + 1);
	last = 1;
	for(int i = 2; i <= n + 1; i++)
		if(a[i] != a[last])
		{
			m[i] = i - 1;
			last = i; 
		}
		else m[i] = m[i - 1];
	for(int i = (fac[0] = 1); i <= n; i++)
		fac[i] = 1ll * fac[i - 1] * i % mod;
	inv[n] = fpow(fac[n], mod - 2);
	for(int i = n - 1; i >= 0; i--)
		inv[i] = 1ll * inv[i + 1] * (i + 1) % mod; 
	for(int i = 1; i <= n; i++)
	{
		if(m[i] == m[n]) break; 
		ans = (ans + 1ll * a[i] * C(n, n - m[i]) % mod * fac[m[i]] % mod * fac[n - m[i] - 1] % mod) % mod; 
	}
	printf("%d
", ans); 
	return 0; 
}
原文地址:https://www.cnblogs.com/ztlztl/p/12208313.html