AtCoder Regular Contest 104 E Random LIS
首先期望转化成 \(\text{LIS}\) 总和除以方案总数(即 \(a_i\) 乘积)不必多说了。观察可发现题目 \(n\) 特别小,考虑 \(O(n^n)\) 枚举 \(x_i\) 的相对大小关系(排名),固定排名后算出 \(\text{LIS}\),再计算这种排名对应的方案数。
于是现在问题变成了有 \(m\) 个数,每个数的上界为 \(b_i\),要求序列单调递增的方案数。考虑直接套 CF1295F Good Contest 的做法,\(b_i\) 离散化后设 \(f_{i,j}\) 为第 \(i\) 个数位于值域第 \(j\) 段的方案数。转移枚举以 \(i\) 为右端点的极长值域位于同一段的区间左端点 \(k\),以及 \(k-1\) 位于哪个段。系数是在 \([1,len_j]\) 中选 \(i-k+1\) 个互不相同的数的方案数(为 \(\binom{len_j}{i-k+1}\))。可得:
\[f_{i,j} \gets \sum\limits_{k=1}^{i-1} \sum\limits_{x=1}^{j-1} \binom{len_j}{i-k+1} f_{k-1,x}
\]
暴力计算即可。
总时间复杂度大概是 \(O(n^{n+5})\)(没仔细算,实际远远达不到)。
code
// Problem: E - Random LIS
// Contest: AtCoder - AtCoder Regular Contest 104
// URL: https://atcoder.jp/contests/arc104/tasks/arc104_e
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
//
// Powered by CP Editor (https://cpeditor.org)
#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
typedef pair<ll, ll> pii;
const int maxn = 12;
const ll mod = 1000000007;
inline ll qpow(ll b, ll p) {
ll res = 1;
while (p) {
if (p & 1) {
res = res * b % mod;
}
b = b * b % mod;
p >>= 1;
}
return res;
}
ll n, fac[maxn], ifac[maxn], a[maxn], b[maxn], c[maxn], g[maxn], ans;
ll h[maxn], lsh[maxn], f[maxn][maxn];
inline ll C(ll n, ll m) {
if (n < m || n < 0 || m < 0) {
return 0;
} else {
ll ans = ifac[m];
for (int i = 0; i < m; ++i) {
ans = ans * (n - i) % mod;
}
return ans;
}
}
inline ll work() {
mems(h, 0x3f);
ll m = 0;
for (int i = 1; i <= n; ++i) {
h[b[i]] = min(h[b[i]], a[i]);
m = max(m, b[i]);
}
int tot = 0;
for (int i = 1; i <= m; ++i) {
lsh[++tot] = h[i];
}
lsh[++tot] = 0;
sort(lsh + 1, lsh + tot + 1);
tot = unique(lsh + 1, lsh + tot + 1) - lsh - 1;
for (int i = 1; i <= m; ++i) {
h[i] = lower_bound(lsh + 1, lsh + tot + 1, h[i]) - lsh;
}
mems(f, 0);
f[0][1] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 2; j <= h[i]; ++j) {
// printf("%d %d\n", i, j);
ll mn = h[i];
for (int k = i; k; --k) {
mn = min(mn, h[k]);
if (j > mn) {
break;
}
for (int x = 1; x < j; ++x) {
if (!f[k - 1][x]) {
continue;
}
f[i][j] = (f[i][j] + C(lsh[j] - lsh[j - 1], i - k + 1) * f[k - 1][x] % mod) % mod;
}
}
}
}
ll ans = 0;
for (int i = 2; i <= tot; ++i) {
ans = (ans + f[m][i]) % mod;
}
// if (ans) {
// printf("b: ");
// for (int i = 1; i <= n; ++i) {
// printf("%lld ", b[i]);
// }
// putchar('\n');
// printf("h: ");
// for (int i = 1; i <= m; ++i) {
// printf("%lld ", h[i]);
// }
// putchar('\n');
// printf("%lld\n", ans);
// }
return ans;
}
void dfs(int d) {
if (d > n) {
for (int i = 1; i <= n; ++i) {
c[i] = b[i];
}
sort(c + 1, c + n + 1);
for (int i = 1; i <= n; ++i) {
if (c[i] - c[i - 1] > 1) {
return;
}
}
ll mx = 0;
for (int i = 1; i <= n; ++i) {
g[i] = 1;
for (int j = 1; j < i; ++j) {
if (b[j] < b[i]) {
g[i] = max(g[i], g[j] + 1);
}
}
mx = max(mx, g[i]);
}
ans = (ans + mx * work() % mod) % mod;
return;
}
for (int i = 1; i <= n; ++i) {
b[d] = i;
dfs(d + 1);
}
}
void solve() {
scanf("%lld", &n);
fac[0] = 1;
for (int i = 1; i <= n; ++i) {
scanf("%lld", &a[i]);
fac[i] = fac[i - 1] * i % mod;
}
ifac[n] = qpow(fac[n], mod - 2);
for (int i = n - 1; ~i; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % mod;
}
dfs(1);
// printf("ans: %lld\n", ans);
for (int i = 1; i <= n; ++i) {
ans = ans * qpow(a[i], mod - 2) % mod;
}
printf("%lld\n", ans);
}
int main() {
int T = 1;
// scanf("%d", &T);
while (T--) {
solve();
}
return 0;
}