Codeforces 题面传送门 & 洛谷题面传送门

期望好题。

首先拆方差:

\[\begin{aligned}
&E((x-E(x))^2)\\
=&E(x^2)-2E(x)E(E(x))+E(E(x)^2)\\
=&E(x^2)-E(x)^2
\end{aligned}
\]

因此我们只需 \(E(x^2)\) 和 \(E(x)\) 即可求解出答案。

考虑 \(x\) 是什么东西。直接从连通块个数的角度下手异常棘手。不过注意到原图是一个仙人掌,因此假设点数、边数、环数分别为 \(a,b,c\),那么连通块个数 \(x=a-b+c\),这可以看作原本有 \(a\) 个连通块,每加入一条边会少一个连通块,但有 \(c\) 次加边时成环,连通块个数不变。

因此 \(E(x^2)=E((a-b+c)^2)=E(a^2)+E(b^2)+E(c^2)-2E(ab)+2E(ac)-2E(bc)\),\(E(x)=E(a)-E(b)+E(c)\)。

考虑对这九个东西分别计算:

1. \(E(a)\)

显然 \(E(a)=\dfrac{n}{2}\)

2. \(E(b)\)

显然 \(E(b)=\dfrac{m}{4}\),因为每条边有 \(\dfrac{1}{4}\) 的概率存在。

3. \(E(c)\)

假设原仙人掌中第 \(i\) 个环点数为 \(C_i\),那么显然第 \(i\) 个环被保留的概率就是 \(p_i=\dfrac{1}{2^{C_i}}\)

期望环数 \(=\sum\limits_{i=1}^cp_i\),其中 \(c\) 为原仙人掌中环数。

4. \(E(a^2)\)

根据期望的线性性 \(E(a^2)\) 等于每对点同时存在的概率。

考虑对于两个点 \(i,j\):

  • 如果 \(i=j\),那它们同时存在的概率为 \(\dfrac{1}{2}\)
  • 否则它们同时存在的概率为 \(\dfrac{1}{4}\)

化简一下可得 \(E(a^2)=\dfrac{n(n+1)}{4}\)

5. \(E(b^2)\)

根据期望的线性性 \(E(b^2)\) 等于每对边同时存在的概率。

考虑两条边 \(i,j\):

  • 如果 \(i=j\),那它们同时存在的概率为 \(\dfrac{1}{4}\)
  • 如果 \(i,j\) 两条边恰好存在一个公共端点,那么它们同时存在的概率为 \(\dfrac{1}{8}\)
  • 否则它们同时存在的概率为 \(\dfrac{1}{16}\)

对于第一种情况贡献就是 \(E(b)\),直接加上,对于第二种情况就枚举公共点,这样可以算得有多少对边符合第二种情况,剩余的边肯定都属于第三种情况了。

6. \(E(c^2)\)

根据期望的线性性 \(E(c^2)\) 等于每对环同时存在的概率。

考虑两个环 \(i,j\),由于原图是仙人掌两个不同的环最多只有一个公共点:

  • 如果 \(i=j\),那它们同时存在的概率为 \(p_i\)
  • 如果 \(i,j\) 两个环恰好存在一个公共点,那它们同时存在的概率为 \(p_i·p_j·2\)
  • 否则它们同时存在的概率为 \(p_i·p_j\)

和 \(E(b^2)\) 的求法类似,第一种情况的贡献就是 \(E(c)\),对于二三两种情况我们先额外将所有 \(i\ne j\) 的 \(p_i·p_j\) 加入答案,再额外枚举所有符合第二类限制的两个环 \(i,j\),再将它们的 \(p_i·p_j\) 累加入答案。具体求法也是枚举公共点然后扫一遍,并维护当前扫过的所有环的 \(p_i\) 之和即可算出贡献。

7. \(E(ab)\)

根据期望的线性性 \(E(ab)\) 等于每个点与每条边同时存在的概率之和。

考虑一个点 \(a\) 和一条边 \(e\):

  • 如果 \(a\) 是 \(e\) 的一个端点,那么它们同时存在的概率为 \(\dfrac{1}{4}\)
  • 否则它们同时存在的概率为 \(\dfrac{1}{8}\)

枚举每个点,然后预处理每个点的度即可算出有多少条边符合第一种情况,有多少条边符合第二种情况。

8. \(E(ac)\)

根据期望的线性性 \(E(ac)\) 等于每个点与每个环同时存在的概率之和。

考虑一个点 \(a\) 和一个环 \(c\):

  • 如果 \(a\) 在 \(c\) 上,那它们同时存在的概率为 \(p_c\)
  • 否则它们同时存在的概率为 \(\dfrac{1}{2}p_c\)

还是按照套路枚举环 \(c\),预处理每个环上的点数即可知道有多少个点符合第一种情况,有多少个点符合第二种情况。

9. \(E(bc)\)

根据期望的线性性 \(E(bc)\) 等于每条边与每个环同时存在的概率之和。

考虑一条边 \(e\) 和一个环 \(c\):

  • 如果 \(e\) 的两个端点都在 \(c\) 上,那它们同时存在的概率为 \(p_c\)
  • 如果 \(e\) 的一个端点在 \(c\) 上,那它们同时存在的概率为 \(\dfrac{1}{2}p_c\)
  • 如果 \(e\) 的两个端点都不在 \(c\) 上,那它们同时存在的概率为 \(\dfrac{1}{4}p_c\)

对于第一种情况还是通过预处理每个环上的点数即可快速算出,第二种情况符合条件的边数即为环上每个点的度数减 \(2\) 之和,剩余的边都是第三种情况。

时间复杂度 \(\mathcal O(n+m)\)。

const int MAXN=5e5;
const int MOD=1e9+7;
const int INV2=MOD+1>>1;
const int INV4=MOD+1>>2;
const int INV8=MOD+1>>3;
const int INV16=((MOD+9>>4)-INV2+MOD)%MOD;
int n,m,hd[MAXN+5],to[MAXN*2+5],nxt[MAXN*2+5],ec=0;
void adde(int u,int v){to[++ec]=v;nxt[ec]=hd[u];hd[u]=ec;}
int dfn[MAXN+5],fa[MAXN+5],tim=0,ipw2[MAXN+5];
vector<int> cyc[MAXN+5],bel[MAXN+5];
int cycnt=0,P[MAXN+5],deg[MAXN+5];
void dfs(int x){
dfn[x]=++tim;
for(int e=hd[x];e;e=nxt[e]){
int y=to[e];
if(!dfn[y]) fa[y]=x,dfs(y);
else if(dfn[y]<dfn[x]&&y!=fa[x]){
cycnt++;
for(int i=x;i^y;i=fa[i]) cyc[cycnt].pb(i),bel[i].pb(cycnt);
cyc[cycnt].pb(y);bel[y].pb(cycnt);
}
}
}
int Ea(){return 1ll*n*INV2%MOD;}
int Eb(){return 1ll*m*INV4%MOD;}
int Ec(){int sum=0;for(int i=1;i<=cycnt;i++) sum=(sum+P[i])%MOD;return sum;}
int Ex(){return (0ll+Ea()-Eb()+Ec()+MOD)%MOD;}
int Eaa(){return 1ll*n*(n+1)%MOD*INV4%MOD;}
int Ebb(){
ll tot=1ll*m*(m-1);int res=1ll*m*INV4%MOD;
for(int i=1;i<=n;i++){
tot-=1ll*deg[i]*(deg[i]-1);
res=(res+1ll*deg[i]*(deg[i]-1)%MOD*INV8)%MOD;
} res=(res+1ll*tot%MOD*INV16)%MOD;
return res;
}
int Ecc(){
ll tot=1ll*cycnt*(cycnt-1);int res=Ec(),sum=0;
for(int i=1;i<=cycnt;i++) res=(res+2ll*sum*P[i])%MOD,sum=(sum+P[i])%MOD;
for(int i=1;i<=n;i++){
int ssum=0;
for(int j:bel[i]) res=(res+2ll*ssum*P[j])%MOD,ssum=(ssum+P[j])%MOD;
} return res;
}
int Eab(){
int res=0;
for(int i=1;i<=n;i++) res=(res+1ll*INV4*deg[i]+1ll*INV8*(m-deg[i]))%MOD;
return res;
}
int Eac(){
int res=0,sm=Ec();
for(int i=1;i<=n;i++){
int ssum=0;
for(int j:bel[i]) ssum=(ssum+P[j])%MOD;
res=(0ll+res+ssum+1ll*INV2*(sm-ssum+MOD))%MOD;
} return res;
}
int Ebc(){
int res=0;
for(int i=1;i<=cycnt;i++) res=(res+1ll*P[i]*cyc[i].size())%MOD;
for(int i=1;i<=cycnt;i++){
int sum_ed=0,rst;
for(int j:cyc[i]) sum_ed+=deg[j]-2;
rst=m-cyc[i].size()-sum_ed;
res=(0ll+res+1ll*P[i]*INV2%MOD*sum_ed+1ll*P[i]*INV4%MOD*rst)%MOD;
} return res;
}
int sqr(int x){return 1ll*x*x%MOD;}
int main(){
scanf("%d%d",&n,&m);
for(int i=(ipw2[0]=1);i<=n;i++) ipw2[i]=1ll*ipw2[i-1]*INV2%MOD;
for(int i=1,u,v;i<=m;i++){
scanf("%d%d",&u,&v);adde(u,v);adde(v,u);
deg[u]++;deg[v]++;
} dfs(1);for(int i=1;i<=cycnt;i++) P[i]=ipw2[cyc[i].size()];
// printf("%d\n",Ec());
printf("%d\n",((0ll+Eaa()+Ebb()+Ecc()-2ll*Eab()-2ll*Ebc()+2ll*Eac()-sqr(Ex()))%MOD+MOD)%MOD);
return 0;
}

Codeforces 1236F - Alice and the Cactus(期望+分类讨论)的更多相关文章

  1. CodeForces - 789B B. Masha and geometric depression---(水坑 分类讨论)

    CodeForces - 789B 当时题意理解的有点偏差,一直wa在了14组.是q等于0的时候,b1的绝对值大于l的时候,当b1的绝对值大于l的时候就应该直接终端掉,不应该管后面的0的. 题意告诉你 ...

  2. [cf1236F]Alice and the Cactus

    首先,我们要用到期望的一个性质: 对于两个随机变量$X$和$Y$(不需要相互独立),有$E(X+Y)=E(X)+E(Y)$ 另外,对于一个仙人掌,令$n$为点数,$m$为边数,$c$为简单环个数,$X ...

  3. Codeforces 521E - Cycling City(点双连通分量+分类讨论)

    Codeforces 题面传送门 & 洛谷题面传送门 大家都是暴力找生成树然后跳路径,代码不到 50 行(暴论)的一说--好,那本蒟蒻决定提供一种代码 150 行,但复杂度也是线性的分类讨论做 ...

  4. Codeforces 685C - Optimal Point(分类讨论+乱搞)

    Codeforces 题面传送门 & 洛谷题面传送门 分类讨论神题. 首先看到最大值最小,一眼二分答案,于是问题转化为判定性问题,即是否 \(\exists x_0,y_0,z_0\) 满足 ...

  5. Codeforces 1513F - Swapping Problem(分类讨论+乱搞)

    Codeforces 题目传送门 & 洛谷题目传送门 简单题,难度 *2500 的 D2F,就当调节一下一模炸裂了的自闭的心情,稍微写写吧. 首先我看到这题的第一反应是分类讨论+数据结构,即枚 ...

  6. Codeforces 460D Little Victor and Set --分类讨论+构造

    题意:从区间[L,R]中选取不多于k个数,使这些数异或和尽量小,输出最小异或和以及选取的那些数. 解法:分类讨论. 设选取k个数. 1. k=4的时候如果区间长度>=4且L是偶数,那么可以构造四 ...

  7. Educational Codeforces Round 63 (Rated for Div. 2) D. Beautiful Array 分类讨论连续递推dp

    题意:给出一个 数列 和一个x 可以对数列一个连续的部分 每个数乘以x  问该序列可以达到的最大连续序列和是多少 思路: 不是所有区间题目都是线段树!!!!!! 这题其实是一个很简单的dp 使用的是分 ...

  8. 【树链剖分】【dfs序】【LCA】【分类讨论】Codeforces Round #425 (Div. 2) D. Misha, Grisha and Underground

    一棵树,q次询问,每次给你三个点a b c,让你把它们选做s f t,问你把s到f +1后,询问f到t的和,然后可能的最大值是多少. 最无脑的想法是链剖线段树……但是会TLE. LCT一样无脑,但是少 ...

  9. Codeforces 1461F - Mathematical Expression(分类讨论+找性质+dp)

    现场 1 小时 44 分钟过掉此题,祭之 大力分类讨论. 如果 \(|s|=1\),那么显然所有位置都只能填上这个字符,因为你只能这么填. scanf("%d",&n);m ...

随机推荐

  1. Redis 高阶数据类型重温

    今天这个专题接着上一篇 Redis 的基本数据类型 继续讲解剩下的高阶数据类型:BitMap.HyperLogLog 和 GEO hash.这些数据结构的底层也都是基于我们前面说的 5 种 基本类型, ...

  2. 分库分表利器之Sharding Sphere(深度好文,看过的人都说好)

    Sharding-Sphere Sharding-JDBC 最早是当当网内部使用的一款分库分表框架,到2017年的时候才开始对外开源,这几年在大量社区贡献者的不断迭代下,功能也逐渐完善,现已更名为 S ...

  3. Hadoop面试题(四)——YARN

    1.简述hadoop1与hadoop2 的架构异同 1)加入了yarn解决了资源调度的问题. 2)加入了对zookeeper的支持实现比较可靠的高可用. 2.为什么会产生 yarn,它解决了什么问题, ...

  4. 力扣 - 剑指 Offer 53 - I. 在排序数组中查找数字 I

    题目 剑指 Offer 53 - I. 在排序数组中查找数字 I 思路1 一般来说,首先想到的是使用一个变量,从头开始遍历整个数组,记录target数组出现的次数,但是这样的时间复杂度是O(n),还是 ...

  5. 热身训练4 Article

    Article 在这个学期即将结束时,DRD开始写他的最后一篇文章. DRD使用著名的Macrohard的软件World来写他的文章. 不幸的是,这个软件相当不稳定,它总是崩溃. DRD需要在他的文章 ...

  6. Shadertoy 教程 Part 5 - 运用SDF绘制出更多的2D图形

    Note: This series blog was translated from Nathan Vaughn's Shaders Language Tutorial and has been au ...

  7. Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例

    Loto实践干货(8)loto示波器在LED台灯调光问题维修中的应用案例 一位客户最近觉得觉得他的LED台灯好闪, 于是拆了看看,里面的控制板是这样的: 干掉双色调光功能,只调亮度的话闪烁的状况能好转 ...

  8. c++ template 实现一个简单的"栈"

    一: 实现一个简单的swap 原来我们写swap一定会这样写: 对于int类型的: swap(const int &x,const int &y) { int temp; temp = ...

  9. 装了这几个IDEA插件,基本上一站式开发了!

    前言 前几天有社区小伙伴私聊我,问我都用哪些IDEA插件,我的IDEA的主题看起来不错. 作为一个开源作者,每周要code大量的代码,提升日常工作效率是我一直追求的,在众多的IDEA插件中,我独钟爱这 ...

  10. JMeter跨线程组保持登录(多线程组共享cookie)

    使用__setProperty设置全局变量: 1.jmeter中创建一个登录请求,然后执行,察看结果树-->查看返回cookie信息,我的是在Response data中的 Response h ...