[HDU-6305] RMQ Similar Sequence

RMQ Similar Sequence http://acm.hdu.edu.cn/showproblem.php?pid=6305

Chiaki has a sequence A={a1,a2,,an} A = { a 1 , a 2 , … , a n } . Let RMQ(A,l,r) R M Q ( A , l , r ) be the minimum i(lir) i ( l ≤ i ≤ r ) such that ai a i is the maximum value in al,al+1,,ar a l , a l + 1 , … , a r .

Two sequences A A and B are called \textit{RMQ Similar}, if they have the same length n and for every 1lrn 1 ≤ l ≤ r ≤ n , RMQ(A,l,r)=RMQ(B,l,r) R M Q ( A , l , r ) = R M Q ( B , l , r ) .

For a given the sequence A={a1,a2,,an} A = { a 1 , a 2 , … , a n } , define the weight of a sequence B={b1,b2,,bn} B = { b 1 , b 2 , … , b n } be ∑i=1nbi (i.e. the sum of all elements in B B ) if sequence B and sequence A A are RMQ Similar, or 0 otherwise. If each element of B is a real number chosen independently and uniformly at random between 0 and 1, find the expected weight of B B .

官方题解

MQ-Similar实际上就是 A B B 的笛卡尔树一样,这样我们就有了一个二叉树,然后可以在树上分析了。

考虑到B中有元素相同的概率是 0 ,于是可以假设 B B 里面元素互不相同,也就是说可以假定是一个排列。

显然,符合笛卡尔树的排列就是这个树的拓扑序列个数,就是n!2sizei。然后显然每个排列期望的和是 n2 n 2 ,于是答案就是 n2sizei n 2 ∏ s i z e i

#include <bits/stdc++.h>
using namespace std;

using namespace std;
typedef long long ll;
typedef pair <int, int> pii;
const ll MOD = 1000000007;
const int MAXN = (int)1e6 + 5;

int l[MAXN], r[MAXN], vis[MAXN], stk[MAXN], inv[MAXN], sz[MAXN], n, ans, T;
pii a[MAXN];

void dfs(int v) {
    if(l[v]) dfs(l[v]);
    if(r[v]) dfs(r[v]);
    sz[v] = 1 + sz[l[v]] + sz[r[v]];
    ans = (1LL * ans * inv[sz[v]]) % MOD;
}

int build() { //建笛卡尔树
    int top = 0;
    rep(i, 1, n + 1) l[i] = r[i] = vis[i] = 0;
    rep(i, 1, n + 1) {
        int k = top;
        while(k > 0 && a[stk[k - 1]] < a[i]) --k;
        if(k) r[stk[k-1]] = i;
        if(k<top) l[i] = stk[k];
        stk[k++] = i;
        top = k;
    }
    rep(i, 1, n + 1) vis[l[i]] = vis[r[i]] = 1;
    int ret = 0;
    rep(i, 1, n + 1) if(vis[i] == 0) ret = i;
    return ret;
}

void slove() {
    int ret = build();
    ans = 1;
    memset(sz, 0x00, sizeof(int) * (n + 1));
    dfs(ret);
    printf("%d\n", (int)(1LL * ans * n % MOD * inv[2] % MOD));
}

int main()
{
    inv[1] = 1; 
    rep(i, 2, MAXN) inv[i] = 1LL * inv[MOD%i]*(MOD-MOD/i)%MOD;
    while(scanf("%d", &T) != EOF) {
        while(T--) {
            scanf("%d", &n);
            rep(i, 1, n + 1) {
                scanf("%d", &a[i].first);
                a[i].second = -i;
            }
            slove();
        }
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值