2020牛客暑期多校训练营(第九场)C

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;
}
原文地址:https://www.cnblogs.com/mollnn/p/13798955.html