【CTSC2019】随机立方体(二项式反演)

mac2025-12-03  13

传送门


题解:

以下假设 n ≤ m ≤ l n\leq m\leq l nml

一看模数我还以为要上多项式全家桶。。。

按照套路,看到“恰好”二字觉得并不对劲。。。

但是你当你尝试计算“至少”的时候你觉得更不对劲,因为显然有大量的重复部分被计算,感觉计算“至少”这个东西本来就要容斥。容斥套容斥???

考虑计算钦定 i i i个位置成为极大的概率 f i f_i fi。然后二项式反演得到答案为 a n s = ∑ i = k n ( i k ) f [ i ] ans=\sum_{i=k}^n{i\choose k}f[i] ans=i=kn(ki)f[i]

首先是拿出 i i i个位置,然后给它们规定大小顺序。即 A n , i ⋅ A m , i ⋅ A l , i A_{n,i}\cdot A_{m,i}\cdot A_{l,i} An,iAm,iAl,i

然后从大到小一个一个考虑,显然将所有掌控区间拿出来,最大的极大值就是这些拿出来的所有位置的最大值,然后将只被这个极大值掌控的位置丢掉,考虑剩下的,也就是 i − 1 i-1 i1个极大值的情况,发现本质上和前面的相同。

i i i个极大值的时候掌控的总位置数为 n m l − ( n − i ) ( m − i ) ( l − i ) nml-(n-i)(m-i)(l-i) nml(ni)(mi)(li),钦定一个位置为这些位置的最大值的概率就是这个值的倒数。

于是得到钦定的 i i i个位置按照顺序成为最大值的概率为 ∏ j = 1 i 1 n m l − ( n − j ) ( m − j ) ( l − j ) \prod_{j=1}^i\frac{1}{nml-(n-j)(m-j)(l-j)} j=1inml(nj)(mj)(lj)1

支持一个线性求逆元即可。


代码:

#include<bits/stdc++.h> #define ll long long #define re register #define cs const using std::cerr; using std::cout; cs int mod=998244353; inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);} inline int dec(int a,int b){a-=b;return a+(a>>31&mod);} inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;} inline int po(int a,int b){ int r=1;for(;b;b>>=1,a=mul(a,a)) if(b&1)r=mul(r,a);return r; } inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;} inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;} inline void Mul(int &a,int b){a=mul(a,b);} inline void ex_gcd(int a,int b,int &x,int &y){ if(!b){x=1,y=0;return ;}ex_gcd(b,a%b,y,x);y-=a/b*x; } inline int inv(int a){ int x=1,y=1;ex_gcd(mod,a,y,x); return x+(x>>31&mod); } cs int N=5e6+7; int fac[N],ifc[N],v[N],iv[N]; void init_fac(){ fac[0]=1; for(int re i=1;i<N;++i)fac[i]=mul(fac[i-1],i); ifc[N-1]=inv(fac[N-1]); for(int re i=N-1;i;--i)ifc[i-1]=mul(ifc[i],i); } inline int A(int n,int m){return mul(fac[n],ifc[n-m]);} inline int C(int n,int m){return mul(fac[n],mul(ifc[n-m],ifc[m]));} signed main(){ #ifdef zxyoi freopen("cube.in","r",stdin); #endif int T;scanf("%d",&T);init_fac(); while(T--){ int n,m,l,k; scanf("%d%d%d%d",&n,&m,&l,&k); if(n>m)std::swap(n,m); if(n>l)std::swap(n,l); int nml=mul(n,mul(m,l)),prod=1; for(int re i=1;i<=n;++i)Mul(prod,v[i]=dec(nml,mul(n-i,mul(m-i,l-i)))); prod=inv(prod);int ans=0,tmp=mul(mul(fac[n],fac[m]),mul(fac[l],ifc[k])); for(int re i=n;i>=k;--i){ int val=mul(mul(tmp,fac[i]),mul(mul(ifc[n-i],ifc[m-i]),mul(ifc[l-i],ifc[i-k]))); Mul(val,prod);Mul(prod,v[i]); ((i^k)&1)?Dec(ans,val):Inc(ans,val); } cout<<ans<<"\n"; } return 0; }
最新回复(0)