HDU 6305 笛卡尔树

题目链接


题意:
给定一个数组 a ,现在存在一个数组 b ,其元素值在 [ 0 , 1 ] 随机生成,若数组 a , b 生成的笛卡尔树同构,则数组 b 的价值为 b [ i ] ,否则为 0 ,求数组 b 的期望价值为多少?


思路:
首先构建 a 数组的笛卡尔树,此时有一个结论是:
b 数组与 a 数组同构的概率是

p = i = 1 n 1 s i z e [ i ]

s i z e [ i ] 代表以第 i 个节点为根的子树大小。

为什么成立呢?假设我们先生成 n [ 0 , 1 ] 的互不相等的数,随后全排列,假设 a 数组中最大的数的下标为 i d ,则 b 数组中下标 i d 处也应该填入最大的数,而此条件成立的概率为 1 n 。此时对于 i d 左右的两个区间,同样需要满足该条件,即最大值下标应该相同。将所有独立区间满足条件的概率乘起来,即为总概率。

随后,因为每个数都在[0,1]中等概率随机生成,则期望值为 1 / 2 ,故 n 个数和的期望值为 n / 2
此时期望价值为:

n 2 p + ( 1 p ) 0 = n 2 s i z e [ i ]

d f s 统计一下笛卡尔树每个节点为根的子树的 s i z e 即可。


代码:

#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;
}

猜你喜欢

转载自blog.csdn.net/wubaizhe/article/details/81193832
今日推荐