2018 Multi-University Training Contest 1 08
题意
给 \(n\) 和 \(a_1,\ a_2,\ ...,\ a_n\)。定义 \(f(a,\ l,\ r)\ =\ min\{i\ |\ a_i\ \geq\ a_j\ (l\ \leq\ j\ \leq\ r)\}\),\(F(b_1,\ b_2,\ ...,\ b_n)\ =\ [\forall\ 1\ \leq\ l\ \leq\ r\ \leq\ n,\ f(a,\ l,\ r)\ =\ f(b,\ l,\ r)]\ \times\ (\sum_{i\ =\ 1}^n\ b_i)\)。
问如果 \(b\) 中每个数均为 \([0,\ 1]\) 中独立的随机的实数,则 \(F(b)\) 的期望是多少,模 \(10^9\ +\ 7\) 输出。
\(1\ \leq\ n\ \leq\ 10^6\)
做法1
每次从 \(a\) 中找到当前的 \(f(a,\ l,\ r)\),然后递归下去,从 \(l\ =\ 1,\ r\ =\ n\) 开始递归,建出树。如果 \(b\) 的树与 \(a\) 的树一样则 \(F(b)\) 不为 \(0\)。
由于 \(b\) 中存在相等的数的概率为 \(0\),所以可以考虑对于任意的一个 \(0\ \leq\ x_1\ <\ x_2\ <\ ...\ <\ x_n\ \leq\ 1\) 和排列 \(p_1,\ p_2,\ ...,\ p_n\),可以得到一个 \(b\),其中 \(b_i\ =\ x_{p_i}\)。
考虑一个 \(p\) 对应的所有的 \(x\),其期望和为 \(\frac{n}{2}\)。于是问题就变成合法 \(p\) 的概率是多少。
合法 \(p\) 的个数就是对 \(a\) 建出的树的拓扑序个数。
代码
#include <bits/stdc++.h>
#ifdef DEBUG
#define debug(...) fprintf(stderr, __VA_ARGS__)
#else
#define debug(...)
#endif
#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif
using namespace std;
const int maxn = 1e6 + 10, lgn = 21, mod = 1e9 + 7;
template <int input_SZ, int output_SZ> struct IO {
char s[input_SZ], t[output_SZ], *a, *b;
IO() { fread(s, 1, input_SZ, stdin); a = s; b = t; }
~IO() { fwrite(t, 1, b - t, stdout); }
char nextchar(char c) {
return *a++;
}
int nextint() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; int x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
long long nextll() {
while(*a != '-' && (*a < '0' || *a > '9')) ++a;
bool flag = 0; long long x = 0;
if(*a == '-') ++a, flag = 1;
while(*a >= '0' && *a <= '9') x = x * 10 + *a++ - '0';
if(flag) x = -x;
return x;
}
void outchar(char c) {
*b++ = c;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x) {
if(!x) { *b++ = '0'; return; }
if(x < 0) *b++ = '-', x = -x;
static char s[20], *a;
a = s;
while(x) {
T y = x / 10;
*a++ = x - y * 10 + '0';
x = y;
}
while(a != s) *b++ = *--a;
if(b - t > output_SZ - 25) { fwrite(t, 1, b - t, stdout); b = t; }
return;
}
template<typename T> void outnum(T x, char c) {
return outnum(x), outchar(c);
}
};
IO<(1 << 25) | 10, (1 << 24) | 10> io;
int a[maxn], st[maxn][lgn], LOG[maxn], n, T, q[maxn], fnt, rar, l[maxn], r[maxn], par[maxn], sz[maxn], dp[maxn], fac[maxn], ifac[maxn];
int pow_mod(int x, int n = mod - 2) { int y = 1; while(n) { if(n & 1) y = (long long) y * x % mod; x = (long long) x * x % mod; n >>= 1; } return y; }
int cmax(int i, int j) { return a[i] < a[j] ? j : i; }
int Q(int l, int r) {
if(l == r) return st[l][0];
int lg = LOG[r - l + 1];
return cmax(st[l][lg], st[r - (1 << lg) + 1][lg]);
}
void PB(int s, int t, int f = -1) {
par[rar] = f;
l[rar] = s;
r[rar] = t;
sz[rar] = 0;
dp[rar] = 1;
q[rar] = Q(s, t);
++rar;
return;
}
int C(int n, int m) { return n < m || m < 0 ? 0 : (long long) fac[n] * ifac[m] % mod * ifac[n - m] % mod; }
void solve() {
n = io.nextint();
for (int i = 1; i <= n; ++i) a[i] = io.nextint(), st[i][0] = i;
for (int lg = 1; lg < lgn; ++lg) {
int l = 1 << lg - 1;
for (int i = 1; i + l <= n; ++i) st[i][lg] = cmax(st[i][lg - 1], st[i + l][lg - 1]);
}
fnt = rar = 0;
PB(1, n);
while(fnt != rar) {
int l = ::l[fnt], r = ::r[fnt], i = ::q[fnt]; ++fnt;
if(l < i) PB(l, i - 1, fnt - 1);
if(i < r) PB(i + 1, r, fnt - 1);
}
for (int i = rar - 1; i; --i) {
++sz[i];
int j = par[i];
dp[j] = (long long) dp[j] * C(sz[j] + sz[i], sz[i]) % mod * dp[i] % mod;
sz[j] += sz[i];
}
io.outnum((int)((long long) dp[0] * n % mod * ifac[n] % mod * ifac[2] % mod), '\n');
return;
}
int main() {
for (int i = 2; i < maxn; ++i) LOG[i] = LOG[i >> 1] + 1;
for (int i = fac[0] = 1; i < maxn; ++i) fac[i] = (long long) fac[i - 1] * i % mod;
ifac[maxn - 1] = pow_mod(fac[maxn - 1]);
for (int i = maxn - 1; i; --i) ifac[i - 1] = (long long) ifac[i] * i % mod;
T = io.nextint();
while(T--) solve();
return 0;
}