abc242EX(最值反演)

题意:[1,n]的区间,给m个区间 [ l i , r i ] [l_i,r_i] [li,ri],每次随机选一个区间覆盖,求[1,n]被覆盖的期望次数。(n,m<=400)

Solution1:最值反演

\quad 由最值反演 E [ m a x ( S ) ] = ∑ T 包含于 S ( − 1 ) ∣ T ∣ + 1 E [ m i n ( T ) ] E[max(S)]=\sum_{T包含于S}(-1)^{|T|+1}E[min(T)] E[max(S)]=T包含于S(1)T+1E[min(T)]

\quad 这里max(S)等价于[1,n]中最晚被覆盖的点的覆盖时刻。

\quad 主要思路是枚举某个区间作为最早覆盖时刻的容斥系数贡献。

\quad f i , j f_{i,j} fi,j表示前i个数中第i个数选(后面n-i个数不选),且与j个已知区间有交的容斥系数贡献。

\quad c n t l , r cnt_{l,r} cntl,r表示[l,r]这个区间被已知区间覆盖到的次数,

b i b_i bi表示i点被已知区间覆盖到的次数。

\quad 有转移方程 f i , k + b i − c n t i , j = ∑ j = 0 i − 1 − f j , k f_{i,k+b_i-cnt_{i,j}} = \sum_{j=0}^{i-1}-f_{j,k} fi,k+bicnti,j=j=0i1fj,k

\quad 解释一下,对于含i(不含i+1n)的集合的系数贡献,可以从前面含j(不含j+1n)的集合的系数贡献转移过来。首先由于选i,集合大小会+1,那么符号要反一下。从j转移过来,也就是说1j-1不关心,j选,j+1i-1不选,i选,i+1~n不选。

\quad 所以对于第二维要减去覆盖到[j+1,i-1]的已知区间数,这个等价于覆盖i的区间数+覆盖j的区间数 - 覆盖[i,j]的区间数。

​ 算出 f i , j f_{i,j} fi,j后怎么算答案呢?

\quad f i , j f_{i,j} fi,j——含i不含i+1~n的集合的容斥系数贡献,前面说要枚举E[min(T)],即选到有交的某个区间的期望次数,m个选到其中j个中的一个的期望次数,即 m j \frac{m}{j} jm

a n s = ∑ f i , j ∗ m j \quad ans =\sum f_{i,j}*\frac{m}{j} ans=fi,jjm

Solution2: nb但不容易想到的期望推导

首先直接上结论: a n s = ∑ s t a t e p s t a t e ∗ m c n t , 其中 s t a t e 表示拿到 c n t 个区间,且这些区间的并不是 [ 1 , n ] ans = \sum_{state}p_{state}*\frac{m}{cnt},其中state表示拿到cnt个区间,且这些区间的并不是[1,n] ans=statepstatecntm,其中state表示拿到cnt个区间,且这些区间的并不是[1,n]

前面是拿到cnt个区间,且它们的并不是[1,n],即必定还要拿其他的区间,后面就是第一次拿到其他区间的期望次数。所有状态的往下走一步的期望次数和就是答案,很nb的计算方法。

PS:第一次见期望这样算,不过式子确实没毛病😊

f i f_i fi表示取i个区间,它们并不为[1,n]的方案数

p s t a t e = C ( m , c n t ) − f c n t C ( m , c n t ) p_{state}=\frac{C(m,cnt)-f_{cnt}}{C(m,cnt)} pstate=C(m,cnt)C(m,cnt)fcnt

现在只要求 f i f_i fi即可,可以用dp求出。

将已知区间排序后,dp[i] [j] [k]表示前i个已知区间,选了k条,它们的并为[1,j]的方案数。

要求的就是 f i = d p [ n ] [ m ] [ i ] f_i=dp[n][m][i] fi=dp[n][m][i]

转移方程,枚举加入的区间 [ l i , r i ] [l_i,r_i] [li,ri]

1,当 j < l i − 1 j<l_i-1 j<li1时, d p i , j , k ← d p i − 1 , j , k dp_{i,j,k}\leftarrow dp_{i-1,j,k} dpi,j,kdpi1,j,k

2,当 l i − 1 < = j < = r i l_i-1<=j<=r_i li1<=j<=ri时, d p i , j , k ← d p i − 1 , j , k , d p i − 1 , j , k − 1 → d p i , r i , k dp_{i,j,k}\leftarrow dp_{i-1,j,k},dp_{i-1,j,k-1} \rightarrow dp_{i,r_i,k} dpi,j,kdpi1,j,k,dpi1,j,k1dpi,ri,k

3,当 j > r i j>r_i j>ri时, d p i , j , k ← d p i − 1 , j , k + [ k > 0 ] d p i − 1 , j , k − 1 dp_{i,j,k} \leftarrow dp_{i-1,j,k} + [k>0]dp{i-1,j,k-1} dpi,j,kdpi1,j,k+[k>0]dpi1,j,k1

最值反演

const int mod=998244353;
const double eps=1e-8;
ll qsm(int a,int b){
    ll ans = 1,tmp=a;
    while( b ){
        if( b&1 ) ans = ans * tmp%mod;
        tmp = tmp * tmp%mod;
        b>>=1;
    }
    return ans;
}
int n,m;
int cnt[N][N];//区间[l,r]被给定区间覆盖的次数
pii line[N];
int f[N][N];//1~i-1任意,i必选,i+1~n不选的集合的∑容斥系数
int b[N];//点i被已知区间覆盖的次数
bool in(int i,int j){return line[j].fi<=i&&i<=line[j].se;}
signed main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif  
    IOS;
    cin>>n>>m;
    _for(i,1,m) cin>>line[i].fi>>line[i].se;
    _for(i,1,n)
        _for(j,1,n)
            _for(k,1,m) 
                if( in(i,k)&&in(j,k) ) cnt[i][j]++;
    _for(i,1,n)
        _for(j,1,m) b[i] += in(i,j);
    f[0][0] = mod-1;//空集容斥,不过最后对答案没有贡献
    _for(i,1,n)
        _for(j,0,i-1)
            _for(k,0,m){
                f[i][k+b[i]-cnt[i][j]] = (f[i][k+b[i]-cnt[i][j]] - f[j][k]+mod)%mod;
            }
    int ans = 0;
    _for(i,1,n){
        _for(j,0,m) ans = (ans + f[i][j]*m%mod*qsm(j,mod-2)%mod)%mod;
    }
    cout<<ans<<endl;
    AC; 
}

nb期望

const int N=400+10;
const int mod=998244353;
const double eps=1e-8;
pii line[N];
int n,m;
int f[N][N][N];
int fac[N],ni_f[N];
ll qsm(int a,int b){
    ll ans=1,tmp=a;
    while( b ) {
        if( b&1 ) ans = ans * tmp%mod;
        tmp = tmp * tmp%mod;
        b>>=1;
    }
    return ans;
}
void ini(){
    int maxn = 400;
    fac[0]=1;
    _for(i,1,maxn) fac[i] =  (fac[i-1] * i)%mod;
    ni_f[maxn] = qsm(fac[maxn],mod-2);
    _rep(i,maxn-1,0) ni_f[i] = ni_f[i+1] * (i+1)%mod;
}
ll C(int n,int m){
    if( m==n || m==0 ) return 1;
    if( n < m ) return 0;
    return fac[n] * ni_f[n-m]%mod * ni_f[m]%mod;
}
//fijk,排序后,前i条线段,选k条,它们的并为[1,j],方案数
signed main(){
#ifndef ONLINE_JUDGE
    freopen("in.txt", "r", stdin);
#endif  
    IOS;
    ini();
    cin>>n>>m;
    _for(i,1,m) cin>>line[i].fi>>line[i].se;
    sort(line+1,line+1+m);
    f[0][0][0]=1;
    _for(i,1,m){
        _rep(j,n,0){
            _for(k,0,m){
                auto [L,R] = line[i];
                if( j < L - 1 ) f[i][j][k] += f[i-1][j][k],f[i][j][k]%=mod;
                else if( j<=R ){
                    f[i][j][k] += f[i-1][j][k],f[i][j][k]%=mod;
                    if( k ) f[i][R][k] += f[i-1][j][k-1],f[i][R][k]%=mod;
                }
                else {
                    f[i][j][k] += f[i-1][j][k],f[i][j][k]%=mod;
                    if( k ) f[i][j][k] += f[i-1][j][k-1],f[i][j][k]%=mod;
                }
            }
        }
    }
    int ans = 0;
    _for(i,0,m){
        ans = (ans + (C(m,i) - f[m][n][i] +mod)%mod * qsm(C(m,i),mod-2)%mod * m %mod 
            * qsm(m-i,mod-2)%mod)%mod;
    }
    cout<<ans<<endl;
    AC; 
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值