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

Page Views Count

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

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

f(k)=i=kn1(ik)g(i)g(k)=i=kn1(ik)(1)ikf(i)

现在要求 f(k)

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

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

(n1knRik)j=1UijnRi×(Uij)Ri1=(n1knRik)j=1UijnRi×l=0Ri1(Ri1l)Uil×(1)Ri1l×jRi1l=(n1knRik)l=0Ri1(Ri1l)(1)Ri1lUil×j=1Uijn1l=(n1knRik)h(i)

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

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

f(k)=(n1k)i=1m(n1knRik)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;   
}

作者:SoyTony

出处:https://www.cnblogs.com/SoyTony/p/Solution_on_Luogu-P3270.html

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   SoyTony  阅读(38)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
more_horiz
keyboard_arrow_up light_mode palette
选择主题
点击右上角即可分享
微信分享提示