【loj3119】【CTS2019】随机立方体

题目

​ 一个 $ n m l $ 的立方体等概率填入 $ 1-nml $ ;

​ 定义一个位置是极大的当且仅当这个位置比三位坐标的至少一维与之相等的位置的值都大.

​ 询问极大值恰好有\(k\)个的概率

​ $1 \le n,m,l \le 5000000  ,  1 \le k \le 100 , 1 \le T \le 10 $

题解

  • 由于平时不注意部分分所以CTS考得很难看,会改一改写博客的风格QAQ

  • 二项式反演 
    \[ \begin{align} f_i = \sum_{j\le i}(^i_j)g_j \Leftrightarrow g_i = \sum_{j \le i}(-1)^{i-j}(^i_j)f_j \\ f_i = \sum_{j\ge i} (^j_i)g_j \Leftrightarrow g_i=\sum_{j\ge i}(-1)^{j-i}(^j_i)f_j \\ 均可带入验证证明 \end{align} \]

  • 10pts

    直接打表即可

  • 30pts

    \(dp_{i,j,a,b,c}\)表示从大到小填数填了\(i\)个,极大值有\(j\)个,在$ x,y,z \(坐标上占据了\) a,b,c $行;

    复杂度:\(O(n^2m^2l^2min(n,m,l))\)

  • 40pts

    考虑统计先选好\(k\)个位置,最后的概率乘以一个\(\Pi_{j=0}^{k-1}(n-j)(m-j)(l-j)\)

    选好的\(k\)个位置会形成\((n-k)(m-k)(l-1)\)个无关的位置和\(nml-(n-k)(m-k)(l-k)\)个有关位置

    \(dp_{i,j}\)表示已经选了\(j\)个极值点,其它点随意的方案

    还是从大到小考虑,一个非极值点可以放的位置是所有无关位置和已经选过的极值点的有关位置的并

    转移考虑每次一个点是不是极值点就可以了

    最后套用二项式反演即可得到答案

    复杂度:\(O(nmlmin(n,m,l))\)

  • 100 pts

    还是先硬点\(i\)个位置极大的概率之和\(f_i\),只需要考虑关键位置$ i \(个极值都成立的概率\)h_i$:
    \[ \begin{align} a_i &= (n-i)(m-i)(l-i)\\ f_i &= \prod_{j=0}^{i-1}a_j \times h_i \end{align} \]
    直接从大到小考虑所有数是不独立的,不过第一个极大值大于前\(i\)个关键位置并的值和第二个极大值大于前\(i-1\)个关键位置并的值是独立的,所以
    \[ h_i = \prod_{j=1}^{i}\frac{1}{nml-a_j} \]
    注意逆元的技巧即可,最后依旧二项式反演回来

#include<bits/stdc++.h>
#define ll long long 
#define mod 998244353
using namespace std;
const int N=5000010;
int T,n,m,l,k,f[N],h[N],a[N],A,tmp,fac[N],inv[N];
char gc(){
    static char*p1,*p2,s[1000000];
    if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
    return(p1==p2)?EOF:*p1++;
}
int rd(){
    int x=0;char c=gc();
    while(c<'0'||c>'9')c=gc();
    while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+c-'0',c=gc();
    return x;
}
int pw(int x,int y){
    int re=1;
    while(y){
        if(y&1)re=(ll)re*x%mod;
        y>>=1;x=(ll)x*x%mod;
    }
    return re;
}
void inc(int&x,int y){x+=y;if(x>=mod)x-=mod;}
void dec(int&x,int y){x-=y;if(x<0)x+=mod;}
int C(int x,int y){return x<y?0:(ll)fac[x]*inv[y]%mod*inv[x-y]%mod;}
int cal(int x){return (ll)(n-x)*(m-x)%mod*(l-x)%mod;}
int main(){
//  freopen("cube.in","r",stdin);
//  freopen("cube.out","w",stdout);
    T=rd();
    for(int i=fac[0]=1;i<N;++i)fac[i]=(ll)fac[i-1]*i%mod;
    inv[N-1]=pw(fac[N-1],mod-2);
    for(int i=N-1;i;--i)inv[i-1]=(ll)inv[i]*i%mod;
    while(T--){
        n=rd();m=rd();l=rd();k=rd();
        A=(ll)n*m%mod*l%mod;
        tmp=min(min(n,m),l);
        if(k>tmp){puts("0");continue;}
        for(int i=a[0]=1;i<=tmp;++i)a[i]=(ll)a[i-1]*cal(i-1)%mod;
        int mul=1;
        for(int i=1;i<=tmp;++i)h[i]=(A-cal(i)+mod)%mod,mul=(ll)mul*h[i]%mod;
        mul=pw(mul,mod-2);
        for(int i=tmp;i;--i){
            f[i]=(ll)a[i]*mul%mod;
            mul=(ll)mul*h[i]%mod;
        }
        int ans=0;
        for(int i=k;i<=tmp;++i)if((i-k)&1)dec(ans,(ll)C(i,k)*f[i]%mod);
        else inc(ans,(ll)C(i,k)*f[i]%mod);
        printf("%d\n",ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Paul-Guderian/p/10903676.html