P3270 [JLOI2016] 成绩比较

\(a_i=N-R_i,n=N-1\)

先不考虑有多少人被碾压,计算出符合排名限制的方案数。枚举每门课和 B 神在每门课中的得分,选出 \(a_i\) 个人得分小于等于他,即:

\[\prod\limits_{i=1}^m \dbinom{n}{a_i} \sum\limits_{j=1}^{U_i} j^{a_i}(U_i-j)^{n-a_i} \]

\(s(x)=\sum\limits_{j=1}^{x} j^{a_i}(U_i-j)^{n-a_i}\),是关于 \(x\)\(n\) 次多项式,直接拉格朗日插值求出 \(s(U_i)\) 即可。

接下来计算出恰好有 \(k\) 个人被碾压的概率。设 \(f_{i,j}\) 表示仅考虑前 \(i\) 门课,恰好有 \(j\) 个人被碾压的概率。初始状态 \(f_{0,n}=1\),根据组合意义可得转移方程为:

\[f_{i,j}=\sum\limits_{p=j}^{n+j-a_i} f_{i-1,p}\times\dfrac{\tbinom{p}{j}\tbinom{n-p}{a_i-j}}{\tbinom{n}{a_i}} \]

最终答案即为 \(f_{n,k}\times \prod\limits_{i=1}^{m} s(U_i)\),时间复杂度 \(O(n^2m)\)

#include<stdio.h>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int N=110,mod=1e9+7;
int n,m,k,U[N],a[N],s[N];
ll ans=1,P[N],I[N],f[N],g[N],dp[N][N];
inline ll ksm(ll a,int b=mod-2)
{
    ll ans=1;
    for(;b;b>>=1,a=a*a%mod)
        if(b&1) ans=ans*a%mod;
    return ans;
}
inline ll C(int n,int m)
    {return P[n]*I[m]%mod*I[n-m]%mod;}
inline ll work(int m,int k)
{
    for(int i=1;i<=min(m,n+1);++i)
        s[i]=(ksm(i,k)*ksm(m-i,n-k)+s[i-1])%mod;
    if(m<=n+1) return s[m];
    f[0]=m,g[n+2]=1;ll ans=0;
    for(int i=1;i<=n+1;++i) f[i]=(m-i)*f[i-1]%mod;
    for(int i=n+1;~i;--i) g[i]=(m-i)*g[i+1]%mod; 
    for(int i=1;i<=n+1;++i)
        ans+=I[i]*I[n+1-i]%mod*f[i-1]%mod*g[i+1]%mod*s[i]%mod*(((n+1-i)&1)?-1:1);
    return (ans%mod+mod)%mod;
}
signed main()
{
    cin>>n>>m>>k;
    P[0]=1;for(int i=1;i<=n;++i) P[i]=P[i-1]*i%mod;
    I[n]=ksm(P[n]);for(int i=n;i;--i) I[i-1]=I[i]*i%mod;
    --n,dp[0][n]=1;for(int i=1;i<=m;++i) cin>>U[i];
    for(int i=1;i<=m;++i) cin>>a[i],a[i]=n-(a[i]-1);
    for(int i=1;i<=m;++i)
        ans=ans*C(n,a[i])%mod*work(U[i],a[i])%mod;
    for(int i=1;i<=m;++i) for(int j=k;j<=a[i];++j)
    {
        for(int p=j;p<=n+j-a[i];++p)
            dp[i][j]+=C(p,j)*C(n-p,a[i]-j)%mod*dp[i-1][p]%mod;
        dp[i][j]=dp[i][j]%mod*ksm(C(n,a[i]))%mod;
    }
    cout<<ans*dp[m][k]%mod<<'\n';
}
posted @ 2024-05-22 15:36  int_R  阅读(40)  评论(2编辑  收藏  举报