杭电2018多校第一场(2018 Multi-University Training Contest 1) 1008.RMQ Similar Sequence (HDU6305) -笛卡尔树+数学期望

6305.RMQ Similar Sequence

这个题的意思就是对于A,B两个序列,任意的l,r,如果RMQ(A,l,r)=RMQ(B,l,r),B序列里的数为[0,1]的实数,B的重量为B的所有元素的和,否则为0。问你B的期望重量是多少。

dls讲题说是笛卡尔树,笛卡尔树是一种特定的二叉树数据结构,具体的看这篇博客吧:【pushing my way】笛卡尔树

这个题就是笛卡尔树同构的问题,假设A的笛卡尔树的子树大小为sz[u],那么序列B与A同构的概率为,因为B中的数满足均匀分布(因为B中的元素为[0,1]中的任意实数),所以每个位置的期望值为(0+1)/2,那么B的重量总和为n/2,所以B的重量的期望值为

贴一下官方题解:

RMQ-Similar实际上就是A和B的笛卡尔树一样,这样我们就有了一个二叉树,然后可以在树上分析了。 考虑到B中有元素相同的概率是0,于是可以假设B里面元素互不相同,也就是说可以假定是一个排列。 显然,符合笛卡尔树的排列就是这个树的拓扑序列个数,就是。然后显然每个排列期望的和是,于是答案就是

代码(参考别人的模板):

 1 //1008-6305-RMQ的概念、笛卡尔树模板题,同构求bi的拓扑序个数
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<cstdlib>
 8 #include<cassert>
 9 #include<queue>
10 #include<vector>
11 #include<stack>
12 using namespace std;
13 typedef long long ll;
14 const int maxn=1e6+10;
15 const int inf=0x3f3f3f3f;
16 const int mod=1e9+7;
17
18 stack<int>st;
19 ll inv[maxn];
20 int n;
21
22 struct node{
23     int val,sz;
24     int l,r,par;
25 }t[maxn];
26
27
28 void init()
29 {
30     for(int i=0;i<=n;i++)
31         t[i].l=0,t[i].r=0,t[i].par=0,t[i].sz=0;//初始化
32     t[0].val=inf;
33     while(!st.empty())
34         st.pop();
35     st.push(0);
36 }
37
38 void build()
39 {
40     for(int i=1;i<=n;i++){
41         while(!st.empty()&&t[st.top()].val<t[i].val)//从栈顶往栈底遍历,
42             st.pop();
43         int par=st.top();
44         t[i].par=par;//i.par为st.pop()
45         t[i].l=t[par].r;
46         t[t[par].r].par=i;
47         t[par].r=i;//右子树
48         st.push(i);
49     }
50 }
51
52 void dfs(int u)
53 {
54     if(u==0) return ;
55     t[u].sz=1;
56     dfs(t[u].l);
57     dfs(t[u].r);
58     t[u].sz+=t[t[u].l].sz+t[t[u].r].sz;
59 }
60
61 void Inv(){//扩展gcd求逆元
62     inv[1]=1;
63     for(int i=2;i<maxn;i++)
64         inv[i]=inv[mod%i]*(mod-mod/i)%mod;
65 }
66
67 int main()
68 {
69     int T;
70     Inv();
71     scanf("%d",&T);
72     while(T--){
73         scanf("%d",&n);
74         init();
75         for(int i=1;i<=n;i++)
76             scanf("%d",&t[i].val);
77         build();
78         dfs(t[0].r);
79
80         ll ans=n*inv[2]%mod;
81         for(int i=1;i<=n;i++)
82             ans=ans*inv[t[i].sz]%mod;
83         printf("%lld\n",ans);
84     }
85 }

代码(标程):

 1 #include <cstdio>
 2 #include <functional>
 3 #include <algorithm>
 4 #include <vector>
 5 #include <queue>
 6
 7 using int64 = long long;
 8
 9 const int mod = 1e9 + 7;
10
11 int main() {
12   int T;
13   scanf("%d", &T);
14   for (int cas = 1; cas <= T; ++cas) {
15     int n;
16     scanf("%d", &n);
17     std::vector<int> a(n);
18     for (int i = 0; i < n; ++i) {
19       scanf("%d", &a[i]);
20     }
21
22     std::vector<int> left(n, -1), right(n, -1), stk(n), parent(n, -1);
23     for (int i = 0, top = 0; i < n; ++i) {
24       int last = -1;
25       while (top && a[i] > a[stk[top - 1]]) {
26         last = stk[--top];
27       }
28       if (top) {
29         right[stk[top - 1]] = i;
30         parent[i] = stk[top - 1];
31       }
32       left[i] = last;
33       if (last != -1) parent[last] = i;
34       stk[top++] = i;
35     }
36
37     std::vector<int> inv(n + 2, 1);
38     for (int i = 2; i < n + 2; ++i) {
39       inv[i] = int64(mod - mod / i) * inv[mod % i] % mod;
40     }
41
42     using pii = std::pair<int, int>;
43     {
44       std::vector<pii> a(n), b(n);
45       std::queue<int> queue;
46       std::vector<int> cnt(n);
47       for (int i = 0; i < n; ++i) {
48         a[i] = b[i] = {inv[2], 0};
49         if (left[i] == -1 && right[i] == -1) {
50           queue.push(i);
51         }
52         cnt[i] = (left[i] != -1) + (right[i] != -1);
53       }
54       while (!queue.empty()) {
55         int u = queue.front(); queue.pop();
56         pii res = {(int64)a[u].first * inv[a[u].second] % mod * b[u].first % mod * inv[b[u].second] * 2 % mod, a[u].second + b[u].second + 1};
57         int p = parent[u];
58         if (p == -1) {
59           printf("%d\n", res.first);
60           break;
61         }
62         if (cnt[p] == 2) a[p] = res;
63         else if (cnt[p] == 1) b[p] = res;
64         --cnt[p];
65         if (cnt[p] == 0) queue.push(p);
66       }
67     }
68   }
69   return 0;
70 }

讲道理,还是有点不太清楚,还不熟练,多学习一下。

溜了。。。

原文地址:https://www.cnblogs.com/ZERO-/p/9395257.html

时间: 2024-08-02 23:46:55

杭电2018多校第一场(2018 Multi-University Training Contest 1) 1008.RMQ Similar Sequence (HDU6305) -笛卡尔树+数学期望的相关文章

杭电2018多校第一场(2018 Multi-University Training Contest 1) 1001.Maximum Multiple (HDU6298)-数学思维题(脑子是个好东西,可惜我没有)

暑假杭电多校第一场,这一场是贪心场,很多贪心的题目,但是自己太菜,姿势挫死了,把自己都写吐了... 2018 Multi-University Training Contest 1 HDU6298.Maximum Multiple 题目意思就是给你一个n,找出来三个数x,y,z, 使得n=x+y+z,而且x,y,z都是n的因数,并且x*y*z为最大值,让你输出来x*y*z的最大值.如果没有满足条件的情况就输出-1. 由1=1/2+1/3+1/6=1/3+1/3+1/3=1/2+1/4+1/4,所

2014多校第一场A题 || HDU 4861 Couple doubi

题目链接 题意 : 有K个球,给你一个数P,可以求出K个值,(i=1,2,...,k) : 1^i+2^i+...+(p-1)^i (mod p).然后女朋友先取,再xp取,都希望赢,如果女朋友能赢输出YES,否则输出NO 思路 :这个题,在纸上算算差不多就出来结果了,因为要赢,所以一开始必定拿大的,根据规律可以发现最后的那个取余结果不是0就是某个数,所以就看那个数有奇数个还是偶数个即可. 官方题解: 1 #include <stdio.h> 2 #include <string.h&g

2014多校第一场 I 题 || HDU 4869 Turn the pokers(费马小定理+快速幂模)

题目链接 题意 : m张牌,可以翻n次,每次翻xi张牌,问最后能得到多少种形态. 思路 :0定义为反面,1定义为正面,(一开始都是反), 对于每次翻牌操作,我们定义两个边界lb,rb,代表每次中1最少时最少的个数,rb代表1最多时的个数.一张牌翻两次和两张牌翻一次 得到的奇偶性相同,所以结果中lb和最多的rb的奇偶性相同.如果找到了lb和rb,那么,介于这两个数之间且与这两个数奇偶性相同的数均可取到,然后在这个区间内求组合数相加(若lb=3,rb=7,则3,5,7这些情况都能取到,也就是说最后的

暑期多校 第一场

A: 描述: 代码: 1 #include <iostream> 2 #include <stdio.h> 3 #include <math.h> 4 #include <string.h> 5 using namespace std; 6 7 int k,p; 8 int a[104]; 9 //void solve(){ 10 // int ans=0; 11 // for(int i=1;i<=k;i++){ 12 // ans=0; 13 //

2014多校第一场D题 || HDU 4864 Task (贪心)

题目链接 题意 : 用N台机器,M个任务,每台机器都有一个最大工作时间和等级,每个任务有一个需要工作时间和一个等级.如果机器完成一个任务要求是:机器的工作时间要大于等于任务的时间,机器的等级要大于等于任务的等级.一台机器只能完成一个任务,一个任务只能被一台机器完成.每个机器完成一个任务公司能够获得500*xi+2*yi (此处xy都是指被完成的任务的).输出所有机器能完成的最多任务数,和最大盈利. 思路 :贪心,自己做的时候想了各种排序都不对,没有考虑到500*xi+2*yi 这个公式的重要性.

2014多校第一场J题 || HDU 4870 Rating(DP || 高斯消元)

题目链接 题意 :小女孩注册了两个比赛的帐号,初始分值都为0,每做一次比赛如果排名在前两百名,rating涨50,否则降100,告诉你她每次比赛在前两百名的概率p,如果她每次做题都用两个账号中分数低的那个去做,问她最终有一个账号达到1000分需要做的比赛的次数的期望值. 思路 :可以直接用公式推出来用DP做,也可以列出210个方程组用高斯消元去做. (1)DP1:离散化.因为50,100,1000都是50的倍数,所以就看作1,2,20.这样做起来比较方便. 定义dp[i]为从 i 分数到达i+1

2014多校第一场 E 题 || HDU 4865 Peter&#39;s Hobby (DP)

题目链接 题意 : 给你两个表格,第一个表格是三种天气下出现四种湿度的可能性.第二个表格是,昨天出现的三种天气下,今天出现三种天气的可能性.然后给你这几天的湿度,告诉你第一天出现三种天气的可能性,让你求出最可能出现的天气序列 . 思路 : 定义第 i 天叶子湿度为hum[i].第 i 天,天气为 j 的最大概率为dp[i][j].wealea[i][j]表示天气为 i 叶子为j的概率,weawea[i][j]表示今天天气为 i 明天天气为j的概率,st[i]表示第一天天气为i的概率.pre[i]

多校第一场 费马小定理+模拟+组合数学

A题:Couple doubi 链接:http://acm.hdu.edu.cn/showproblem.php?pid=4861 这题逗逼了,刚开始根本就没什么思路,刚开始看题的时候有点像费马小定理,但是这个定理我只知道,然后没用过.看了下定义,有点不一样的是反着的,然后反着的我又不会转化,尼玛,就这样错过了最好的解题方法.然后队友又理解错题意了.WA了多发,然后我重新看了下题意,然后队友才发觉理解错题意了,然后找了规律才A. 代码比较短,就不贴了,真的写吧. if(k/(p-1)&1) pu

HDU 5288 OO&#39;s sequence (2015多校第一场 二分查找)

OO's Sequence Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 955    Accepted Submission(s): 358 Problem Description OO has got a array A of size n ,defined a function f(l,r) represent the nu