2020牛客暑期多校训练营Groundhog and Gaming Time(数学期望,线段树,逆元)
Groundhog and Gaming Time
题目描述
样例
input:
6
2 2
1 2
1 4
1 5
3 5
3 6
output:
405536771
题目大意
给定nnn个区间(Li,Ri)(L_i,R_i)(Li,Ri),每个区间有12\frac{1}{2}21的概率取到,假设取了mmm个,求:
E(∣(L1,R1)∩(L2,R2)∩(L3,R3)...∩(Lm,Rm)∣2)E(|(L_1,R_1)\cap(L_2,R_2)\cap(L_3,R_3)...\cap(L_m,R_m)|^2)E(∣(L1,R1)∩(L2,R2)∩(L3,R3)...∩(Lm,Rm)∣2)
其中E(A)E(A)E(A)表示AAA的期望。
分析
首先我们看到期望先回顾期望的几种解法:
1、E(A)=P(A)∗A1、E(A)=P(A)*A1、E(A)=P(A)∗A 显然不行,如果所有的情况枚举显然超时了。
2、解方程2、解方程2、解方程 这题也没有想再来一瓶那样的可以列出简单的方程,否定。
3、期望dp3、期望dp3、期望dp 这是官方的做法,比较繁琐,但是也可以做。
4、解决单位的期望后累加4、解决单位的期望后累加4、解决单位的期望后累加 这是本篇博客介绍的做法,代码简单。
我们首先来考虑去掉平方之后怎么做。其实是比较简单的,我们不妨画个图简绍一下。
如果有①②③三个区间,我们可以将它们离散化在一条直线上,然后左右端点都分开,得到了1∼51\sim 51∼5的小线段,然后我们对于每个区间都考虑一下:
比如1号线段,如果要取到1号,那么肯定要取区间①,并且②③都不能取,否则∩就不是1号了,因此其概率是18\frac{1}{8}81,总共8种取法,一种满足,因此期望是∣1区间∣8\frac{|1区间|}{8}8∣1区间∣。
同样的,可以得到:
2号,概率是取①,取②或者取①和②,为38\frac{3}{8}83,期望就乘上长度就可以了……
那么对于一段线段,我们可以统计有多少区间是覆盖它的,然后算一下再除以所有的情况就可以了。
以上是去掉平方之后的,但是题目中是有平方的,因此,我们需要将平方搞回去。那么我们假设对于区间iii的期望是xix_ixi,则有:
E=(x1+x2+...+xn)2E=(x_1+x_2+...+x_n)^2E=(x1+x2+...+xn)2
=x1(x1+x2+...+xn)+x2(x1+x2+...+xn)+...+xn(x1+x2+...+xn)\,\,\,\,\,\,=x_1(x_1+x_2+...+x_n)+x_2(x_1+x_2+...+x_n)+...+x_n(x_1+x_2+...+x_n)=x1(x1+x2+...+xn)+x2(x1+x2+...+xn)+...+xn(x1+x2+...+xn)
可以发现,对于一个xix_ixi,可以直接在平方中给它拆开来。
具体一点,就拿上面的栗子:
我们考虑x2x_2x2,那么有这些式子:
E=(x1+x2)2+x22+(x2+x3+x4)2E=(x_1+x_2)^2+x_2^2+(x_2+x_3+x_4)^2E=(x1+x2)2+x22+(x2+x3+x4)2//即取区间①,区间①②,区间②的情况累加
这里我们考虑x2x_2x2对答案的贡献有以下:
x2(x1+x2)x_2(x_1+x_2)x2(x1+x2)//取区间①
x2∗x2x_2*x_2x2∗x2//取区间①②
x2(x2+x3+x4)x_2(x_2+x_3+x_4)x2(x2+x3+x4)//取区间②
那么经过上面去掉平方的经验,x2x_2x2应该是很好求的,重点是解决后面一坨东西怎么算。
同样的,我们考虑这些后面的一段在给定的区间中出现了几次。
假设我当前枚举到线段QQQ,并且它出现在区间中aaa次,则有:
E(Q)=2a−12n∗∣Q∣E(Q)=\frac{2^a-1}{2^n}*|Q|E(Q)=2n2a−1∗∣Q∣
显然,不能全部都不取,这里的式子都比较好推的,可以结合上面的图示理解一下。
那么对于所有的线段PiP_iPi贡献为:
贡献=∑E(Pi)=\sum E(P_i)=∑E(Pi)
=∣Pi∣∗∑j(2aj−12n∗∣Qj∣)\,\,\,\,\,\,\,\,\,\,=|P_i|*\sum_j(\frac{2^{a_j}-1}{2^n}*|Q_j|)=∣Pi∣∗∑j(2n2aj−1∗∣Qj∣)
=∣Pi∣∗∑j(2aj2n∗∣Qj∣)−不取的期望\,\,\,\,\,\,\,\,\,\,=|P_i|*\sum_j(\frac{2^{a_j}}{2^n}*|Q_j|)-不取的期望=∣Pi∣∗∑j(2n2aj∗∣Qj∣)−不取的期望
那么中间的那段可以用线段树来维护,然后最后再减去不取的。
更多的细节看代码。
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAX=1e9+1;
const int MAXN=1e6+10;
const int MOD=998244353;
ll inv,p[MAXN],l[MAXN],r[MAXN],idl[MAXN],idr[MAXN];
ll ksm(ll a,ll p){ll ret=1;while(p){if(p&1) ret=ret*a%MOD;a=a*a%MOD,p>>=1;}return ret;}
struct tree{int l,r;ll sum,inc;
}tr[MAXN<<2];
void build(int i,int l,int r){tr[i].l=l;tr[i].r=r;tr[i].sum=p[r+1]-p[l]%MOD;tr[i].inc=1;if(l==r) return;int mid=l+r>>1;build(i<<1,l,mid);build(i<<1|1,mid+1,r);
}
void update(int i,int l,int r,ll v){if(tr[i].l>=l&&tr[i].r<=r){tr[i].sum=tr[i].sum*v%MOD;tr[i].inc=tr[i].inc*v%MOD;return;}int mid=tr[i].l+tr[i].r>>1;if(r<=mid) update(i<<1,l,r,v);else if(l>mid) update(i<<1|1,l,r,v);else update(i<<1,l,mid,v),update(i<<1|1,mid+1,r,v);tr[i].sum=(tr[i<<1].sum+tr[i<<1|1].sum)%MOD*tr[i].inc%MOD;
}//线段树区间乘
bool cmpl(int x,int y){return l[x]<l[y];}
bool cmpr(int x,int y){return r[x]<r[y];}
int main()
{inv=ksm(2,MOD-2);//因为有除法所以用逆元int n,m=2;scanf("%d",&n);p[1]=0;p[2]=MAX;//防止错误,将线段的左右端点赋值为0和inffor(int i=1;i<=n;i++){scanf("%d%d",&l[i],&r[i]);p[++m]=l[i];p[++m]=++r[i];//存入所有区间的左右端点,这样可以像上面图示一样分开}sort(p+1,p+1+m);m=unique(p+1,p+1+m)-p-1;//离散化build(1,1,m-1);//线段树存储的是线段的长度,初始的时候都是1for(int i=1;i<=n;i++){l[i]=lower_bound(p+1,p+1+m,l[i])-p;r[i]=lower_bound(p+1,p+1+m,r[i])-p;idl[i]=idr[i]=i;//这是记录从左边数第i个左右端点所属的区间的编号}sort(idl+1,idl+1+n,cmpl);sort(idr+1,idr+1+n,cmpr);//然后按照这个排序int li=1,ri=1;ll ans=0;for(int i=1;i<m;i++){//遍历区间[i,i+1],维护包含该区间的线段的交集的期望。这个期望通过计算所有区间的贡献和得到 //从m个线段,找出a个线段包含区间[i,i+1]。计算这a个线段的交集的期望,等于每个区间的贡献总和。//a个线段,有b个线段覆盖区间[j,j+1],则区间[j,j+1]的贡献=长度*(2^b-1)/2^n。其中-1和/2^n最后再去除 for(li;l[idl[li]]<=i&&li<=n;li++)update(1,l[idl[li]],r[idl[li]]-1,2);//乘上所有在这个区间内的线段贡献for(ri;r[idr[ri]]<=i&&ri<=n;ri++)update(1,l[idr[ri]],r[idr[ri]]-1,inv);//除去所有不在这个区间内的,用inv代替除ans=(ans+tr[1].sum*(p[i+1]-p[i])%MOD)%MOD;//然后累加贡献}ans=(ans-MAX%MOD*MAX%MOD+MOD)%MOD;//这里是去除最后都不取的情况,即处理上面说的-1ans=(ans*ksm(inv,n))%MOD;//这里是/2^nprintf("%lld\n",ans%MOD);
}
END
这段代码有其他的一些注释,可以参考。
这题的思路真的比较厉害,这属于套娃的思想,在原来没有平方的基础上,把平方又拆成同样的问题,太强了。
2020牛客暑期多校训练营Groundhog and Gaming Time(数学期望,线段树,逆元)相关推荐
- 2019牛客暑期多校训练营(第一场场)_I题Points Division(线段树+DP维护区间最大值)
题目链接: https://ac.nowcoder.com/acm/contest/881/I 题意: 给你n个点,每个点的坐标为(xi,yi),有两个权值ai,bi. 现在要你将它分成A,B两部分, ...
- 2021牛客暑期多校训练营1 J-Journey among Railway Stations(线段树+思维转化)
J-Journey among Railway Stations 注意区间合并时是否可行信息的合并. 假设线段树当前左节点lll维护的区间是[L,mid][L,\text{mid}][L,mid],右 ...
- E Groundhog Chasing Death(2020牛客暑期多校训练营(第九场))(思维+费马小定理+质因子分解)
E Groundhog Chasing Death(2020牛客暑期多校训练营(第九场))(思维+费马小定理+质因子分解) 链接:https://ac.nowcoder.com/acm/contest ...
- 2020牛客暑期多校训练营(第六场)
2020牛客暑期多校训练营(第六场) 额,睡了一下午,直接错过了比赛... 文章目录 A African Sort 题意: 题解: 代码: B Binary Vector C Combination ...
- 2020牛客暑期多校训练营(第四场)
2020牛客暑期多校训练营(第四场) 这场属实有点难受 文章目录 A Ancient Distance B Basic Gcd Problem 题目 代码: C Count New String D ...
- 2020牛客暑期多校训练营(第一场)
文章目录 A B-Suffix Array B Infinite Tree C Domino D Quadratic Form E Counting Spanning Trees F Infinite ...
- 2020牛客暑期多校训练营(第二场)
2020牛客暑期多校训练营(第二场) 最烦英语题 文章目录 A All with Pairs B Boundary C Cover the Tree D Duration E Exclusive OR ...
- 2020牛客暑期多校训练营(第七场)J.Pointer Analysis
2020牛客暑期多校训练营(第七场)J.Pointer Analysis 题目链接 题目描述 Pointer analysis, which aims to figure out which obje ...
- 2020牛客暑期多校训练营(第三场)A.Clam and Fish
2020牛客暑期多校训练营(第三场)A.Clam and Fish 题目链接 题目描述 There is a fishing game as following: The game contains ...
- 2020牛客暑期多校训练营(第五场)——E Bogo Sort
2020牛客暑期多校训练营(第五场)--E Bogo Sort 题目描述 Today Tonnnny the monkey learned a new algorithm called Bogo So ...
最新文章
- 解决SVN 每次操作都需要重输入用户名密码问题
- 阿里巴巴在 Serverless 计算领域的探索
- 使用DOM解析常用方法
- c++ primer5th,习题12.24
- 计算机python技术基础知识点_python基础--相关计算机基础知识
- arduino智能浇花系统_arduino+水泵+继电器+RFID
- 《天天数学》连载29:一月二十九日
- 基于节点类的二叉树实现及部分操作函数
- 普通话转粤语_语音转文字评测:几款语音转文字app,你了解多少?
- 微信支付 支付成功后不跳转 ecshop微信支付 如下操作即可
- 设计模式_01单例模式
- Cisco无线AP在复杂企业环境配置指南
- 虚拟机克隆后没有IP
- 网站日志统计案例分析与实现
- 打印系统开发(56)——打印机驱动程序设计指南
- 欧洲机器人实验室盘点
- Windows Mobile下的重力感应器(Gravitational Sensor)开发
- windows 10环境下docker 部署RocketMq和RocketMq-Consol 控制台
- 阿里云王牌架构师杨曦:也谈系统缓存设计误区及高阶使用技巧
- 如何把mac照片导入u盘_macbook air里的相片要怎么放到u盘里?