CF EDU163 F-组合数、范德蒙德卷积

“总感觉这题是诈骗题…”
link:https://codeforces.com/contest/1948/problem/F

[!题意]
\(n\) 个袋子,每个袋子有 \(a_i\) 个金币, \(b_i\) 个银币,金币的价格固定是 \(1\) ,每个银币的价格服从 \(B(1,\frac{1}{2})\) 的分布。
\(q\) 次询问,每次问一段区间 \([l,r]\) 内背包总的价值大于其他背包价值的概率。
\(1\leq n,q\leq 3\times 10^5\)
\(\sum a,\sum b\leq 10^6\)


关键其实是 \(\sum a,\sum b\leq 10^6\),比赛时没看到这个…所以根本没往那边想…(不过没看出来组合数的结果也是我不够熟悉…)

金币价值固定,假设区间内有 \(n\) 个银币,区间外有 \(m\) 个银币,则所求概率形如 $$\sum_{x=0}^n \sum_{y=0}^m \binom{n}{x}\binom{m}{y}(\frac{1}{2})^{n+m}[x-y\geq A]$$
因为 \(n+m\) 是固定值,设为 \(S\),反过来枚举 \(x-y=v\) 的值,$$\begin{aligned}\frac{1}{2^{n+m}} \sum_{v=A}^\infty \sum_{y=0}^m \binom{m}{y}\binom{S-m}{y+v}=\frac{1}{2^{n+m}} \sum_{v=A}^\infty \sum_{y=0}^m \binom{m}{m-y}\binom{S-m}{y+v}= \frac{1}{2^{m+m}} \sum_{v=A}^\infty \binom{S}{m+v}\end{aligned}$$
最后一步就是用到了范德蒙德卷积:

\[\sum_{i=0}^k \binom{n}{i}\binom{m}{k-i}=\binom{n+m}{k} \]

Q:这个式子的上界是 \(k\) ,而你求和的对象也喝范德蒙德卷积的形式不一样,上面用的 \(y\) 只求和到了 \(m\) 而不是 \(m+v\) 没问题吗(不用仔细检查一下吗)?
A:毕竟叫卷积…其实只需要check下指标的和是否固定,以及下指标是否跑遍了所有值(\(m-y\) 跑遍了 \(0\sim m\),同时如果 \(y>m\) 的话组合数是0,这并不影响恒等式的正确性)

最后答案就变成上指标固定的组合数求和了,预处理前缀和即可

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fastio ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0)
using namespace std;
typedef long long ll;
const int MOD=998244353;
int ksm(int a,int b){
    int ret=1;a%=MOD;
    for(;b;b>>=1,a=(ll)a*a%MOD)if(b&1)ret=(ll)ret*a%MOD;
    return ret;
}
const int N=2e6+5;
int n,q,a[N],b[N],sa[N],sb[N],fact[N],inv_fact[N],pre[N];
int main(){
    fastio;
    fact[0]=1;
    rep(i,1,N-5)fact[i]=(ll)fact[i-1]*i%MOD;
    inv_fact[N-5]=ksm(fact[N-5],MOD-2);
    for(int i=N-5;i>=1;i--)inv_fact[i-1]=(ll)inv_fact[i]*i%MOD;
    cin>>n>>q;
    rep(i,1,n){
        cin>>a[i];
        sa[i]=sa[i-1]+a[i];
    }
    rep(i,1,n){
        cin>>b[i];
        sb[i]=sb[i-1]+b[i];
    }
    pre[0]=1;
    rep(i,1,sb[n])pre[i]=(pre[i-1]+(ll)fact[sb[n]]*inv_fact[i]%MOD*inv_fact[sb[n]-i])%MOD;
    int pw=ksm(2,sb[n]),inv_pw=ksm(pw,MOD-2);
    while(q--){
        int l,r;
        cin>>l>>r;
        int A=sa[n]-2*(sa[r]-sa[l-1])+1,y=sb[n]-(sb[r]-sb[l-1]);
        if(A+y<0)cout<<1<<' ';
        else if(A+y>sb[n])cout<<0<<' ';
        else cout<<(ll)(pw+MOD-pre[A+y-1])*inv_pw%MOD<<' ';
    }
    return 0;
}

另一个CF的题:CF785E(https://codeforces.com/contest/785/problem/E),基本会遇到一样形式的式子。

posted @ 2024-03-27 21:26  yoshinow2001  阅读(5)  评论(0编辑  收藏  举报