2020牛客暑期多校训练营(第九场)C - Groundhog and Gaming Time - 概率期望,线段树
作者:互联网
Description
给定 \(n\) 个区间,每个区间有 \(1/2\) 的概率被选中,求区间交的长度的平方的期望。
Solution
要求区间交的长度的平方的期望,就是要求所有选择方案的区间交集长度平方的和,将平方拆掉,即枚举每个小段算它的贡献,这个贡献即这个小段的长度乘以限制这个小段选中时,所有方案的区间交长度的和。为了求后者,定义覆盖了刚才枚举的小段的所有线段为当前存在的线段,那么我们再次枚举所有小段,每个小段的贡献就是它的长度乘以包含它的方案数,设后面枚举的这个小段被所有当前存在的线段覆盖的次数为 \(x\),则这个方案数为 \(2^x-1\)。
于是最终我们要求的东西可以被写成这样的形式
\[\sum_{i} |P_i| \sum_{j} \frac{2^{f(i,j)}-1} {2^n} |P_j| \]其中 \(f(i,j)\) 表示所有覆盖了小段 \(i\) 的线段覆盖小段 \(j\) 的次数。
实际求解时,先将 \(-1\) 项提出来,其和就等于数轴长度平方除以 \(2^n\),前面的部分,\(i\) 暴力枚举,\(j\) 用线段树维护一下即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1000005;
const int mod = 998244353;
const int inv2 = (mod+1)/2;
const int oo = 1e9+1;
map <int,int> mp;
int sum[N*4],tag[N*4],breakpoint[N],n,ind,ans,len;
void change(int p,int v)
{
sum[p]=(sum[p]*v)%mod;
tag[p]=(tag[p]*v)%mod;
}
void pushup(int p)
{
sum[p]=(sum[p*2]+sum[p*2+1])%mod;
tag[p]=1;
}
void pushdown(int p)
{
if(tag[p]!=1)
{
change(p*2,tag[p]);
change(p*2+1,tag[p]);
tag[p]=1;
}
}
void build(int p,int l,int r)
{
if(l==r)
{
sum[p]=breakpoint[l+1]-breakpoint[l];
tag[p]=1;
}
else
{
build(p*2,l,(l+r)/2);
build(p*2+1,(l+r)/2+1,r);
pushup(p);
}
}
void modify(int p,int l,int r,int ql,int qr,int v)
{
if(l>qr || r<ql) return;
if(l>=ql && r<=qr)
{
change(p,v);
}
else
{
pushdown(p);
modify(p*2,l,(l+r)/2,ql,qr,v);
modify(p*2+1,(l+r)/2+1,r,ql,qr,v);
pushup(p);
}
}
int query(int p,int l,int r,int ql,int qr)
{
if(l>qr || r<ql) return 0;
if(l>=ql && r<=qr)
{
return sum[p];
}
else
{
pushdown(p);
return (query(p*2,l,(l+r)/2,ql,qr)+query(p*2+1,(l+r)/2+1,r,ql,qr))%mod;
}
}
struct Range
{
int l,r;
} range[N];
struct Operation
{
int l,r,val;
};
vector <Operation> vecOperation[N];
signed main()
{
ios::sync_with_stdio(false);
mp[0]++;
mp[oo]++;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>range[i].l>>range[i].r;
++range[i].r;
len+=range[i].r-range[i].l;
mp[range[i].l]++;
mp[range[i].r]++;
}
for(auto it=mp.begin();it!=mp.end();it++) it->second=++ind, breakpoint[ind]=it->first;
breakpoint[ind+1]=breakpoint[ind];
for(int i=1;i<=n;i++) range[i].l=mp[range[i].l], range[i].r=mp[range[i].r];
build(1,1,ind);
for(int i=1;i<=n;i++)
{
vecOperation[range[i].l].push_back({range[i].l,range[i].r,2});
vecOperation[range[i].r].push_back({range[i].l,range[i].r,inv2});
}
for(int i=1;i<=ind;i++)
{
for(auto op:vecOperation[i])
{
modify(1,1,ind,op.l,op.r-1,op.val);
}
ans+=sum[1]*(breakpoint[i+1]-breakpoint[i])%mod;
ans%=mod;
}
ans-=oo*oo%mod;
ans%=mod;
ans+=mod;
ans%=mod;
for(int i=1;i<=n;i++) ans=(ans*inv2)%mod;
cout<<ans<<endl;
return 0;
}
标签:Gaming,int,++,sum,多校,牛客,range,tag,mp 来源: https://www.cnblogs.com/mollnn/p/13798955.html