首页 > 其他分享 >CF1540B Tree Array 题解

CF1540B Tree Array 题解

时间:2022-09-22 20:01:18浏览次数:76  
标签:概率 int 题解 ll lca Tree lis CF1540B 节点

CF1540B Tree Array

给定一棵 \(n\) 个节点的树。
对于这棵树,我们通过下列方法来生成一个序列:

  1. 等概率选择这 \(n\) 个节点中的一个节点,并对这个节点打上标记(初始时没有节点被打上标记);
  2. 在所有没被打上标记且与至少一个打上标记的节点相连的节点中等概率选择一个节点并对这个节点打上标记;
  3. 重复步骤 2 直到所有节点都被打上标记,此时生成的序列就是所有节点编号按照节点被打上标记的时间排序后的形成的序列。

求生成序列的期望逆序对数对 \(10^9+7\) 取模后的值。
\(2\leq n\leq200;\) 给出的是棵树。

显然所有步骤 2 操作得出的点与步骤一得出的点构成一个连通块。不妨枚举每个点作为步骤 1 得到的点,让他们作为树根,分别求出期望后求和再除以 \(n\)。

对每一对可能存在逆序对求其存在的概率,概率求和即为以某个点为根的逆序对期望。即假设 \(a>b\),那么求出 \(a\) 号点比 \(b\) 号点先选择的概率

同时这个问题又等价于从 \(lca(a,b)\) 开始取点,\(a\) 比 \(b\) 先选择到的概率。

无论现在所选取的点有哪些,所有能进一步选择的点选择概率相等,更具体地,每一个状态选择两个子状态的概率相等,哪怕它有多个子状态,但我们只关心这两个。

所以我们只需 \(lca(a,b)\) 到 \(a\) 的路径上一共取多少个点和到 \(b\) 的路径上取多少个点即可推出 \(a\) 点比 \(b\) 点先取的概率。

定义 \(f_{i,j}\) 为距离 \(a\) 点 \(i\) 个单位,\(b\) 点 \(j\) 个单位,先走到 \(a\) 点的概率,\(f_{0,i}=0\)。如果我们顺推的话(直接对应加粗的结论),可以得出。

\[f_{i+1,j}\gets f_{i+1,j}+\frac{1}{2}f_{i,j}\\ f_{i,j+1}\gets f_{i,j+1}+\frac{1}{2}f_{i,j} \]

或者我们认为

\[f_{i,j}=\frac{f_{i-1,j}+f_{i,j-1}}{2} \]

那么代码实现就很简单了。

const int N=203;
const ll MOD=1000000007;
inline ll fpr(ll b,ll t=MOD-2,ll x=1){
	for(;t;t>>=1,b=b*b%MOD)
		if(t&1)x=x*b%MOD;
	return x;
}
const ll INV2=fpr(2);
int n,lca[N][N],dep[N];
vector<int>edge[N];
ll f[N][N],ans;
inline vector<int> getlca(int u,int f){
	dep[u]=dep[f]+1;
	vector<int>lis;
	for(auto v:edge[u]){
		if(v==f)continue;
		vector<int>tmp=getlca(v,u);
		for(auto x:tmp)lis.push_back(x);
	}lis.push_back(u);
	for(auto x:lis){
		for(auto y:lis)
			if(!lca[x][y])lca[x][y]=u;
	}
	return lis;
}
int main(){
	n=read();
	for(int i=1;i<n;++i){
		int u=read(),v=read();
		edge[u].push_back(v);
		edge[v].push_back(u);
	}
	for(int i=0;i<=n;++i)f[0][i]=1;
	for(int i=1;i<=n;++i){
		for(int j=1;j<=n;++j)
			f[i][j]=(f[i-1][j]+f[i][j-1])%MOD*INV2%MOD;
	}
	for(int i=1;i<=n;++i){
		memset(lca,0,sizeof(lca));
		getlca(i,0);
		for(int j=2;j<=n;++j){
			for(int k=1;k<j;++k){
				int l=lca[j][k];
				ans=(ans+f[dep[j]-dep[l]][dep[k]-dep[l]])%MOD;
			}
		}
	}
	printf("%lld\n",ans*fpr(n)%MOD);
	return 0;
}

标签:概率,int,题解,ll,lca,Tree,lis,CF1540B,节点
From: https://www.cnblogs.com/BigSmall-En/p/16720689.html

相关文章

  • Dev C++中窗口输出中文问题解决
    1、window+R+regedit调出注册表  2、点击Dec_Dev-Cpp_ConsolePauser.exe 3、鼠标左键双击“CodePage”,弹出设置页面。选择“十进制”,输入65001  4、右键点......
  • 【题解】ARC139D Priority Queue 2
    ?思路来源题意假设初始时有一个长度为\(N\),值域为\(M\)的数组\(A\)。现在要进行\(K\)次操作,每次操作从\([1,M]\)中选取一个数,并将其加入\(A\)中。单次操作完......
  • 牛客题解 Channels
    链接:https://ac.nowcoder.com/acm/problem/201606来源:牛客网题解作者岛田小雅要求一段区间内的有效时间总和,第一反应用前缀和。要求\(l\)和\(r\)之间有效时间的和......
  • WebForm中的treeView的简单使用
    我们要使用treeView,首先需要对应树状图关系的表结构,如省市区的结构,大概如下 完成效果图(省市区结构),大概如下: 新增一个citys.aspx页面,在页面中添加treeView<div>......
  • leetcode 105. Construct Binary Tree from Preorder and Inorder Traversal 从前序与
    一、题目大意给定两个整数数组preorder和inorder,其中preorder是二叉树的先序遍历,inorder是同一棵树的中序遍历,请构造二叉树并返回其根节点。示例1:输入:pre......
  • CF1446D1 题解
    传送门题意给定序列\(a_1,a_2,...,a_n\),求最长的满足区间众数有至少两种的区间长度。\(n≤2×10^5,1≤a_i≤min(100,n)\)题解首先,若整个序列有至少两种众数,则答案为......
  • Antd Tree,实现排序拖动,父子层级内外拖动
    拖动属性dropToGap,dropPosition属性解释:dropToGap:boolean类型,true代表拖拽到节点之间的缝隙中,false代表拖拽到节点上,即节点的内容区。dropPosition:拖拽的时候,针对一......
  • 题解【CF1307F Cow and Vacation】
    感觉CF*3300的难度没有这么简单吧(题目传送门。考虑\(\texttt{Bessie}\)运动的过程:起点\(\to\)休息点$\to$\(\cdots\)\(\to\)休息点\(\to\)终点。考虑我们......
  • 2 つの山札题解
    题目链接题意简述:给定两个长度为\(n\)的排列\(A\)和\(B\),按照一下方式生成一个长度为\(2n-2\)的序列:你对每一个排列分别做\(n-1\)次操作,每一次选择一个序列进行......
  • 题解 P7839 「Wdoi-3」夜雀 singing (思路非常好的一道题)
    代码细节非常多的一道题。这里只说思想了先。首先,找到那些安全树。所有的乌鸦最后一定会到达某一棵安全树上。因此,对于每只乌鸦,分别向左和向右暴力寻找,看是否可到达安全......