【BUAA Spring Training 06】二分图匹配 | 笛卡尔树 | 2-SAT | 基环外向树 | 斯坦纳树 | H

第六场春训,谢谢zlc学长 qwq!
E题很有意思哦


【BUAA Spring Training 06】


Tags:二分图匹配 2-SAT 笛卡尔树 基环外向树 斯坦纳树+状压




Problem B. 满意度期望


[B] 题意

对于一个序列 A={a1, a2, a3,... an} \text{A=\{a1, a2, a3,... an\}} A={a1, a2, a3,... an} ,定义 P(A, l, r) \text{P(A, l, r)} P(A, l, r) {al,... ar} \text{\{al,... ar\}} {al,... ar} 中最大数的最左位置。
定义两个序列 A \text{A} A B \text{B} B 相似,当且仅当 ∀   l , r ∈ [ 1 , n ]    s . t .   P(A, l, r) = P(B, l, r) \forall\ l, r \in [1, n] \ \ s.t.\ \ \text{P(A, l, r) = P(B, l, r)}  l,r[1,n]  s.t.  P(A, l, r) = P(B, l, r)

现给定一个有 n \text{n} n 个元素的序列 A \text{A} A ,再随机产生一个也有 n \text{n} n 个元素的序列 B \text{B} B,其中 B \text{B} B 中的所有元素都是从 (0, 1) \text{(0, 1)} (0, 1) 区间内随机选择的。如果 A \text{A} A B \text{B} B 是相似的,那么 B \text{B} B 的"满意度"为 B \text{B} B 中所有值的和,否则为 0 0 0。求 B \text{B} B 的“满意度”的期望。


[B] 思路

学长分享的经验是,遇见这种区间最值的位置关系,就可以考虑用 笛卡尔树 来做。

笛卡尔树是什么?笛卡尔树是由某个序列生成的二叉树,其中序遍历就是原序列。其每棵子树满足:根结点是子树的最值

是不是想到了 Treap ?没错,当区间树使 FHQ Treap \text{FHQ Treap} FHQ Treap 就是一棵笛卡尔树。


那么对于本题我们可以发现,两个序列 A \text{A} A B \text{B} B 是相似的,当且仅当由他们生成的笛卡尔树的 “形态” 是相同的。或者说把数给离散化之后再建笛卡尔树,两棵树相同(两棵树每个结点的子树大小对应相等)则原序列相似。


然后再回到本题。首先 B \text{B} B 数组必定没有相等元素(连续区间上选有限个数,显然选到相等两个数的概率为 0 0 0),然后要求 B \text{B} B A \text{A} A 相似,那么对于每棵笛卡尔树的子树对应的那个小区间 [ l e f t , r i g h t ] [left, right] [left,right],必须要指定某个位置最大。这样的概率显然是 1 r i g h t − l e f t + 1 \frac{1}{right-left+1} rightleft+11 的,或者说 1 s i z e \frac{1}{size} size1 的。

这样 B \text{B} B A \text{A} A 相似的概率就是 A \text{A} A 笛卡尔树的每棵子树的 s i z e size size 的倒数的乘积 Π \Pi Π

而显然 B \text{B} B 数组的每个元素之和的期望是 n × n \times n× 0 + 1 2 \frac{0+1}{2} 20+1 = = == == n 2 \frac{n}{2} 2n

所以满意度期望就是 n Π 2 \frac{n\Pi}{2} 2nΠ


时间复杂度:预处理逆元和建树都是 O ( n ) O(n) O(n) 的。



[B] 代码

/*
 *      If we give,
 *      all we've got,
 *      we will make it through.
 */


#include <cstdio>
#include <climits>
#include <cstring>

#define GC getchar()
#define _SN(x) {char _c=GC,_v=1;for(x=0;_c<48||_c>57;_c=GC)if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=GC);if(_v==-1)x=-x;}
#define _SAN(a,n) {auto _i=0,_n=n;for(;_i<_n;++_i)_SN(a[_i])}
#define _SA(a,l,r) {auto _i=l,_r=r;for(;_i<_r;++_i)_SN(a[_i])}
#define _gS(_1, _2, _3, _sc, ...) _sc
#define sc(...) _gS(__VA_ARGS__,_SA,_SAN,_SN, ...)(__VA_ARGS__)
#define _G1(_1) int _1;sc(_1)
#define _G2(_1,_2) int _1,_2;sc(_1)sc(_2)
#define _G3(_1,_2,_3) int _1,_2,_3;sc(_1)sc(_2)sc(_3)
#define _gG(_1,_2,_3,_get, ...) _get
#define get(...) _gG(__VA_ARGS__,_G3,_G2,_G1, ...)(__VA_ARGS__)
#define _F0N(i,n) for(auto i=0;i<(n);++i)
#define _FLR(i,l,r) for(auto i=(l);i<(r);++i)
#define _gF(_1, _2, _3, _F, ...) _F
#define F(...) _gF(__VA_ARGS__,_FLR,_F0N, ...)(__VA_ARGS__)
#define _FD0(i,n) for(auto i=0;i<=(n);++i)
#define _FDL(i,l,r) for(auto i=(l);i<=(r);++i)
#define _gFD(_1, _2, _3, _FD, ...) _FD
#define FD(...) _gFD(__VA_ARGS__,_FDL,_FD0, ...)(__VA_ARGS__)
#define LL long long
#define ULL unsigned LL
#define PC putchar
template<class T>
void UPRT(const T _){if(_>=10)UPRT(_/10);PC(_%10+48);}

#define Tjj int T;sc(T)while(T--)

const int MN = 3e6+7;
const LL MOD = 1000000007;


LL inv[MN];
int a[MN];

int sta[MN];	// "指针"数组
int lc[MN], rc[MN];
int build(const int n)
{
	memset(lc, 0, sizeof(*lc) * (n+1));
	memset(rc, 0, sizeof(*rc) * (n+1));
	int top = 0;
	sta[top] = 0;			// 哨兵指针取成没用的0
	a[sta[top]] = INT_MAX;	// 哨兵的值,极大。(这和大根堆Treap建树是一回事。小根堆哨兵用极小,大根堆哨兵用极大)

	FD(i, 1, n)
	{
		while (a[sta[top]] < a[i])	// 和小根堆Treap建树相反,这里是栈顶的函值小于当前值,而不是大于
			lc[i] = sta[top--];
		rc[sta[top]] = i;
		sta[++top] = i;
	}

	return rc[0];	// 和Treap建树一样,最后的root是哨兵的右指针
}


LL ans;
int sz[MN];
void dfs(const int u)
{
	sz[u] = 1;
	if (lc[u])
		dfs(lc[u]), sz[u] += sz[lc[u]];
	if (rc[u])
		dfs(rc[u]), sz[u] += sz[rc[u]];

	ans *= inv[sz[u]];
	ans %= MOD;
}


int main()
{
	inv[1] = 1;
	F(i, 2, MN)
		inv[i] = inv[MOD%i] * (MOD-MOD/i) % MOD;

	Tjj
	{
		get(n)
		sc(a, 1, n+1)
		const int ROOT = build(n);

		ans = n * inv[2] % MOD;
		dfs(ROOT);
		UPRT(ans), PC(10);
	}

	return 0;
}




Problem B.

(待更)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值