题目链接:RMQ Similar Sequence
题意
首先给定一个长度为 n n 的整数序列 ,定义 RMQ{A,l,r} R M Q { A , l , r } 表示查找区间 [l,r] [ l , r ] 内的最大值的下标,如果存在多个最大值,则取最左边的数字的下标。现在要构造一个长度为 n n 的序列 ,要求每个数字都是属于区间 [0,1] [ 0 , 1 ] 内的实数,且对于每一个 RMQ{B,l,r} R M Q { B , l , r } ,其询问结果都和 RMQ{A,l,r} R M Q { A , l , r } 相同,问所有满足条件的序列 B B 的 的期望值。
输入
第一行为一个整数 T T ,接下去有 组数据,每组数据第一行为一个整数 n (1≤n≤106) n ( 1 ≤ n ≤ 10 6 ) ,第二行为 n n 个整数 ,数据保证所有 n n 的和不超过 。
输出
输出期望对 109+7 10 9 + 7 取模的结果,如果期望无法被 109+7 10 9 + 7 整除,先化简期望为 pq p q ,保证 p p 和 互质且都为正整数的情况下,输出 a (0≤a≤109+6) a ( 0 ≤ a ≤ 10 9 + 6 ) 的值,要求 p−aq p − a q 能够被 109+7 10 9 + 7 整除。
样例
输入 |
---|
3 3 1 2 3 3 1 2 1 5 1 2 3 2 1 |
输出 |
250000002 500000004 125000001 |
题解
根据题意建立一棵序列 A A 的笛卡尔树,题目即求笛卡尔树与数列 同构的序列 B B 的序列和的期望,由于 内每个数字都是实数,所以任意两个数字相等的概率趋近于 0 0 ,对于每一个节点对应的区间,节点的数字大于该区间内所有数字的概率为 ,其中 soni s o n i 为节点 i i 对应子树的节点数,将所有节点的满足条件的概率相乘,再乘上序列求和的期望值 ,就是答案。最后要求期望对 109+7 10 9 + 7 的取模的结果,就是将结果 pq p q 转化成 p×q−1mod109+7 p × q − 1 mod 10 9 + 7 。
过题代码
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <climits>
#include <cfloat>
#include <cstring>
#include <string>
#include <vector>
#include <list>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
using namespace std;
#define LL long long
const int maxn = 1000000 + 100;
const LL MOD = 1000000007;
LL ans;
LL inv[maxn];
struct Tree {
int root, top, n;
int sta[maxn], l[maxn], r[maxn];
bool vis[maxn];
void build(int *num, int nn) {
n = nn;
top = 0;
memset(l, 0, sizeof(int) * (n + 1));
memset(r, 0, sizeof(int) * (n + 1));
memset(vis, 0, sizeof(bool) * (n + 1));
for(int i = 1; i <= n; ++i) {
int tmp = top;
while(top > 0 && num[sta[top - 1]] < num[i]) {
--top;
}
if(top != 0) {
r[sta[top - 1]] = i;
}
if(top < tmp) {
l[i] = sta[top];
}
sta[top++] = i;
}
for(int i = 1; i <= n; ++i) {
vis[l[i]] = vis[r[i]] = true;
}
for(int i = 1; i <= n; ++i) {
if(!vis[i]) {
root = i;
}
}
}
int dfs(int x) {
int cnt = 1;
if(l[x] != 0) {
cnt += dfs(l[x]);
}
if(r[x] != 0) {
cnt += dfs(r[x]);
}
ans = (ans * inv[cnt]) % MOD;
return cnt;
}
};
int T, n;
int num[maxn];
Tree t;
void Init() {
inv[1] = 1;
for(int i = 2; i < maxn; ++i) {
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}
}
int main() {
#ifdef Dmaxiya
freopen("test.txt", "r", stdin);
#endif // Dmaxiya
ios::sync_with_stdio(false);
Init();
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
ans = (n * inv[2]) % MOD;
for(int i = 1; i <= n; ++i) {
scanf("%d", &num[i]);
}
t.build(num, n);
t.dfs(t.root);
printf("%I64d\n", ans);
}
return 0;
}