题意:
给定一个数组
,现在存在一个数组
,其元素值在
随机生成,若数组
生成的笛卡尔树同构,则数组
的价值为
,否则为
,求数组
的期望价值为多少?
思路:
首先构建
数组的笛卡尔树,此时有一个结论是:
数组与
数组同构的概率是
代表以第 个节点为根的子树大小。
为什么成立呢?假设我们先生成 个 的互不相等的数,随后全排列,假设 数组中最大的数的下标为 ,则 数组中下标 处也应该填入最大的数,而此条件成立的概率为 。此时对于 左右的两个区间,同样需要满足该条件,即最大值下标应该相同。将所有独立区间满足条件的概率乘起来,即为总概率。
随后,因为每个数都在[0,1]中等概率随机生成,则期望值为
,故
个数和的期望值为
。
此时期望价值为:
故 统计一下笛卡尔树每个节点为根的子树的 即可。
代码:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<set>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
const int mod = 1e9 + 7;
const int A = 1e6 + 10;
int n, tot, Sta[A], L[A], R[A], vis[A];
ll Inv[A], ans;
PII a[A];
int dfs(int u){
int siz = 1;
if (L[u]) siz += dfs(L[u]);
if (R[u]) siz += dfs(R[u]);
ans = ans * Inv[siz] % mod;
return siz;
}
int build_Tree(){
tot = 0;
for (int i = 1; i <= n; i++) L[i] = R[i] = vis[i] = 0;
for (int i = 1; i <= n; i++) {
int k = tot;
while (k > 0 && a[Sta[k - 1]] < a[i]) k--;
if (k) R[Sta[k - 1]] = i;
if (k < tot) L[i] = Sta[k];
Sta[k++] = i;
tot = k;
}
for (int i = 1; i <= n; i++) vis[L[i]] = vis[R[i]] = 1;
int rt = 0;
for (int i = 1; i <= n; i++) {
if (vis[i] == 0) rt = i;
}
return rt;
}
int main(){
Inv[1] = 1;
for (int i = 2; i < A; i++) Inv[i] = Inv[mod%i] * (mod - mod / i) % mod;
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
int x;
scanf("%d", &x);
a[i] = make_pair(x, -i);
}
ans = 1LL * n * Inv[2] % mod;
int rt = build_Tree();
dfs(rt);
printf("%I64d\n", ans);
}
return 0;
}