Loading

【题解】Luogu-P3270 JLOI 2016 成绩比较

Page Views Count

式子有点长,步骤有点多,所以写一下。

题目要求恰好 \(k\) 人被吊打的方案数,容易想到二项式反演,设 \(f(k)\) 为钦定 \(k\) 人其他任意的方案数,\(g(k)\) 为恰好 \(k\) 人的方案数。基本式子:

\[f(k)=\sum_{i=k}^{n-1} \dbinom{i}{k} g(i)\Leftrightarrow g(k)=\sum_{i=k}^{n-1} \dbinom{i}{k} (-1)^{i-k} f(i) \]

现在要求 \(f(k)\)

从内层向外看,若在学科 \(i\) 得了 \(j\) 分,则有 \(n-R_i\) 人取值在 \([1,j]\) 间任意,\(R_i-1\) 人取值在 \([j+1,U_i]\) 间任意。这 \(n-R_i\) 人包括起初钦定的 \(k\) 人,剩下的部分不要求多个学科中相同。

于是对于学科 \(i\),可以得出一个:

\[\begin{aligned} &\dbinom{n-1-k}{n-R_i-k}\sum_{j=1}^{U_i} j^{n-R_i}\times (U_i-j)^{R_i-1}\\ =&\dbinom{n-1-k}{n-R_i-k}\sum_{j=1}^{U_i} j^{n-R_i}\times \sum_{l=0}^{R_i-1} \dbinom{R_i-1}{l} U_i^l\times (-1)^{R_i-1-l} \times j^{R_i-1-l}\\ =&\dbinom{n-1-k}{n-R_i-k}\sum_{l=0}^{R_i-1}\dbinom{R_i-1}{l} (-1)^{R_i-1-l} U_i^l\times\sum_{j=1}^{U_i} j^{n-1-l}\\ =&\dbinom{n-1-k}{n-R_i-k}h(i) \end{aligned}\]

后面与 \(k\) 无关就写作 \(h(i)\) 了,最后的自然数幂和可以 \(O(n)\) 求,于是求单个 \(h(i)\)\(O(n^2)\) 的,所有 \(h(i)\)\(O(n^2m)\) 的。

接下来只需要枚举钦定 \(k\) 人的方案以及将相互独立的每个学科之前方案数相乘:

\[f(k)=\dbinom{n-1}{k}\prod_{i=1}^m\dbinom{n-1-k}{n-R_i-k} h(i) \]

最后套上二项式反演,即可求出 \(g(k)\)

点击查看代码
int n,m,k;
int lim[105],rk[105];
int f[105],h[105];
inline int q_pow(int A,int B,int P){
    int res=1;
    while(B){
        if(B&1) res=1ll*res*A%P;
        A=1ll*A*A%P;
        B>>=1;
    }
    return res;
}
int fact[105],fact_inv[105];
int C[105][105];
int Y[105][105];
int pre[105],suf[105];
inline int lagrange(int X,int K){
    pre[0]=1,suf[K+1]=1;
    for(int i=1;i<=K+1;++i) pre[i]=1ll*pre[i-1]*(X-(i-1)+mod)%mod;
    for(int i=K;i>=0;--i) suf[i]=1ll*suf[i+1]*(X-(i+1)+mod)%mod;
    int res=0;
    for(int i=0;i<=K+1;++i){
        int now=1ll*Y[K][i]*pre[i]%mod*suf[i]%mod*fact_inv[i]%mod*fact_inv[K+1-i]%mod;
        if((K+1-i)&1) res=(res-now+mod)%mod;
        else res=(res+now)%mod;
    }
    return res;
}
int ans;
int main(){
    n=read(),m=read(),k=read();
    for(int i=1;i<=m;++i) lim[i]=read();
    for(int i=1;i<=m;++i) rk[i]=read();
    C[0][0]=1;
    for(int i=1;i<=100;++i){
        C[i][0]=C[i][i]=1;
        for(int j=1;j<i;++j){
            C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
    }
    fact[0]=1,fact_inv[0]=1;
    for(int i=1;i<=100;++i) fact[i]=1ll*fact[i-1]*i%mod;
    fact_inv[100]=q_pow(fact[100],mod-2,mod);
    for(int i=99;i>=1;--i) fact_inv[i]=1ll*fact_inv[i+1]*(i+1)%mod;
    for(int i=1;i<n+2;++i){
        int now=1;
        for(int j=0;j<n;++j){
            Y[j][i]=(Y[j][i-1]+now)%mod;
            now=1ll*now*i%mod;
        }
    }
    for(int i=1;i<=m;++i){
        int pw=1;
        for(int j=0;j<rk[i];++j){
            int now=1ll*C[rk[i]-1][j]*pw%mod*lagrange(lim[i],n-1-j)%mod;
            if((rk[i]-1-j)&1) h[i]=(h[i]-now+mod)%mod;
            else h[i]=(h[i]+now)%mod;
            pw=1ll*pw*lim[i]%mod;
        }
    }
    for(int i=k;i<n;++i){
        f[i]=C[n-1][i];
        for(int j=1;j<=m;++j){
            f[i]=1ll*f[i]*C[n-1-i][n-rk[j]-i]%mod*h[j]%mod;
        }
    }
    for(int i=k;i<n;++i){
        int now=1ll*C[i][k]*f[i]%mod;
        if((i-k)&1) ans=(ans-now+mod)%mod;
        else ans=(ans+now)%mod;
    }
    printf("%d\n",ans);
    return 0;   
}
posted @ 2023-01-30 08:21  SoyTony  阅读(35)  评论(0编辑  收藏  举报