【HDU - 6305】RMQ Similar Sequence

@RMQ Similar Sequence@


@题目描述-English@

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

Two sequences A and B are called RMQ Similar, if they have the same length n and for every 1≤l≤r≤n, RMQ(A,l,r)=RMQ(B,l,r).

For a given the sequence A={a1,a2,…,an}, define the weight of a sequence B={b1,b2,…,bn} be ∑i=1nbi (i.e. the sum of all elements in B) if sequence B and sequence 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.

Input
There are multiple test cases. The first line of input contains an integer T, indicating the number of test cases. For each test case:
The first line contains an integer n (1≤n≤10^6) – the length of the sequence.
The second line contains n integers a1,a2,…,an (1≤ai≤n) denoting the sequence.
It is guaranteed that the sum of all n does not exceed 3×10^6.

Output
For each test case, output the answer as a value of a rational number modulo 10^9+7.
Formally, it is guaranteed that under given constraints the probability is always a rational number p/q (p and q are integer and coprime, q is positive), such that q is not divisible by 10^9+7. Output such integer a between 0 and 109+6 that p−aq is divisible by 10^9+7.

Sample Input
3
3
1 2 3
3
1 2 1
5
1 2 3 2 1
Sample Output
250000002
500000004
125000001

@大致题意@

定义RMQ(A, l, r)为最小的x使得A[x]是A[l…r]中的最大值(就是我们通常理解的RMQ)。称两个序列A, B是“RMQ相似”,仅当两个序列的所有相对应的子序列有着相同的RMQ。给出序列A,序列B的每个元素为[0…1]的一个随机实数。如果A,B“RMQ相似”,则B的权值为所有元素之和;否则B的权值为0。
求出B的期望权值。

@分析1@

首先注意到一点,两个序列是RMQ相似当且仅当它们的笛卡尔树同构。因为RMQ问题可以转换为笛卡尔树上的LCA查询。反过来,如果已知所有序列的RMQ,则笛卡尔树任意两点的LCA也就已知。那么与所有点的LCA都为自己的点就是整颗笛卡尔树的根。假如根为 x,则原序列就被分为了不相干的两部分[1…x-1]与[x+1…n],对这两部分进行递归构造就可以唯一构造出一颗笛卡尔树。

@分析2@

然后,一个值域为[0…1]且长度为n的随机序列期望和为n/2。这个比较容易想,因为每个数的期望值为1/2,加起来期望值就肯定为n/2了。
因此,我们只需要求出合法序列的概率P,再用P*n/2就可以了。

@分析3@

因为两个随机实数 x 与 y 相等的概率为0,所以我们假设所有数都互不相同。在笛卡尔树中,根x对应的是这棵子树的最大值,令 siz[x] 表示以 x 为根的子树大小。我们记这颗子树中最大的数为1,第二大的数为 2,以此类推,这样就成为了一个1~siz[x]的排列。因为值是随机的,所以每个排列的出现概率相等。因此根取到合法值(即最大值)的概率P=(siz[x]-1)!siz[x]!=1/siz[x](总排列数siz[x]!个,确定了根的取值排列数变为(siz[x]-1)!个)。所以合法序列的出现概率 = ni=11siz[i] ∏ i = 1 n 1 s i z [ i ]

至此,本题得以解决。

@代码@

如果有什么不懂的,只要不是要求严格证明的都可以在评论区提问或参考代码细节,毕竟我一个中学生也没学过什么连续期望qwq
当时考场没做起,因为当时我们连笛卡尔树是啥都不知道QAQ

#include<cstdio>
#include<stack>
using namespace std;
const int MAXN = 1000000;
const int MOD = int(1E9) + 7;
struct node{
    int key, siz;
    node *ch[2], *fa;
}tree[MAXN + 5], *NIL, *tcnt;
void SetChild(node *x, node *y, int d) {
    if( x != NIL ) x->ch[d] = y;
    if( y != NIL ) y->fa = x;
}
long long ans = 1;
long long inv[MAXN + 5];
void Init() {
    NIL = tcnt = &tree[0];
    NIL->ch[0] = NIL->ch[1] = NIL->fa = NIL;
    ans = 1;
}
void PushUp(node *rt) {
    rt->siz = rt->ch[0]->siz + rt->ch[1]->siz + 1;
}
node *NewNode(int val) {
    tcnt++;
    tcnt->ch[0] = tcnt->ch[1] = tcnt->fa = NIL;
    tcnt->key = val;
    return tcnt;
}
void BuildTree(int n) {
    stack<node*>stk;
    for(int i=1;i<=n;i++) {
        int k;
        scanf("%d", &k);
        node *nw = NewNode(k), *lst = NIL;
        while( !stk.empty() && stk.top()->key < nw->key ) {
            lst = stk.top();
            PushUp(lst);
            ans = (ans * inv[lst->siz]) % MOD;
            stk.pop();
        }
        if( !stk.empty() ) stk.top()->ch[1] = nw;
        nw->ch[0] = lst;
        stk.push(nw);
    }
    while( !stk.empty() ) {
        PushUp(stk.top());
        ans = (ans * inv[stk.top()->siz]) % MOD;
        stk.pop();
    }
}
void solve() {
    Init(); int n;
    scanf("%d", &n);
    BuildTree(n);
    printf("%lld\n", n*inv[2]%MOD*ans%MOD);
}
void GetINV() {
    inv[1] = 1;
    for(int i=2;i<=MAXN;i++)
        inv[i] = MOD - 1LL*(MOD/i)*inv[MOD%i]%MOD;
}
int main() {
    GetINV(); int T;
    scanf("%d", &T);
    for(int i=1;i<=T;i++)
        solve();
}

@end of all@

就是这样,新的一天里,也请多多关照哦(ノω<。)ノ))☆.。~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值