[JLOI2016]成绩比较(容斥+拉格朗日插值)

洛谷P3270 [JLOI2016]成绩比较

要求的是三部分:
1.只考虑从所有人中选出K个人被碾压的方案数

2.只考虑所有人每门成绩高低关系(高于B神或低于B神)的方案数

3.只考虑所有人的具体成绩方案数

答案显然是三数相乘

(下文中下标均从1开始,比如\(文中U_i表示题中U_{i-1}\))

第一部分

显然是\(C_{N-1}^K\)

第二部分

每门都要有\(R-1\)个人的成绩超过B神

考虑\(F(x)=\prod\limits_{i=1}^MC_x^{R_i-1}\)表示每门有R-1个人超过B神的方案数

设d=N-K-1

由容斥得\(G=\sum\limits_{i=0}^d (-1)^{d-i}C_d^i F(i)\)表示d个人不被碾压的方案数

第三部分

首先只考虑一门的方案数

a个人分布在b分里的方案数为\(b^a\)

先考虑B神分数为x时的方案数为\(x^{N-R}(U-x)^{R-1}\)

所以第 i 门的方案数为\(H(i)=\sum\limits_{x=1}^{U_i} x^{N-R_i} (U_i-x)^{R_i-1}\)

\((U_i-x)^{R_i-1}\)二项式定理展开得到\(\sum\limits_{t=0}^{R_i-1}(-x)^t U_i^{R_i-t-1}C_{R_i-1}^t\)

\[\therefore H(i) =\sum\limits_{x=1}^{U_i}x^{N-R_i}\sum\limits_{t=0}^{R_i-1}(-1)^tx^tU_i^{R_i-t-1}C_{R_i-1}^t\\ =\sum\limits_{x=1}^{U_i}\sum\limits_{t=0}^{R_i-1}(-1)^tx^{N-R_i}x^tU_i^{R_i-t-1}C_{R_i-1}^t\\ =\sum\limits_{x=1}^{U_i}\sum\limits_{t=0}^{R_i-1}(-1)^tx^{N-R_i+t}U_i^{R_i-t-1}C_{R_i-1}^t\\ =\sum\limits_{t=0}^{R_i-1}\sum\limits_{x=1}^{U_i}(-1)^tx^{N-R_i+t}U_i^{R_i-t-1}C_{R_i-1}^t\\ =\sum\limits_{t=0}^{R_i-1}(-1)^tU_i^{R_i-t-1}C_{R_i-1}^t\sum\limits_{x=1}^{U_i}x^{N-R_i+t}\\ \]

其中\(\sum\limits_{x=1}^{U_i}x^{N-R_i+t}\)是连续自然数幂和

根据定理: 前N个自然数的K次幂和一定能表示为关于N的K+1次多项式

就可以用拉格朗日插值在\(O(N)\)的时间内算出

那么M门加一起的方案数是\(\prod\limits_{i=1}^M H(i)\), 时间复杂度\(O(N^2M)\)

结论

\(ans=C_{N-1}^K G\prod\limits_{i=1}^MH(i)\)

代码

#include<bits/stdc++.h>
const int N=305;
const int mod=1e9+7;
int Pow(int x,int f=mod-2){
    int re=1;
    while(f){
        if(f&1)re=1ll*re*x%mod;
        f>>=1;
        x=1ll*x*x%mod;
    }
    return re;
}
namespace Lagrange{
    int mul[N];
    int Lagrange(int n,int t,int *f){
        if(t<=n)return f[t];
        int re=0,s=1;
        for(int i=1;i<=n;i++)s=1ll*s*(t-i)%mod;
        for(int i=1;i<=n;i++){
            int tmp=1ll*s*f[i]%mod;
            int div=1ll*mul[i-1]*mul[n-i]%mod;
            div=1ll*div*(t-i)%mod;
            div=Pow(div);
            tmp=1ll*tmp*div%mod;
            if((n-i)&1)re=(re-tmp+mod)%mod;
            else re=(re+tmp)%mod;
        }
        return re;
    }
    void Pre(int t,int *f){
        mul[0]=mul[1]=1;
        for(int i=2;i<=t+2;i++)mul[i]=1ll*mul[i-1]*i%mod;
        for(int i=1;i<=t+2;i++)f[i]=(f[i-1]+Pow(i,t))%mod;
    }
    int f[N];
    int Sum(int n,int t){
        Pre(t,f);
        int re=Lagrange(t+2,n,f);
        return re;
    }
}
int n,m,k,u[N],r[N],c[N][N];
void Init(){
    c[0][0]=1;
    for(int i=1;i<=n;i++){
        c[i][0]=1;
        for(int j=1;j<=i;j++){
            c[i][j]=c[i-1][j-1]+c[i-1][j];
            c[i][j]%=mod;
        }
    }
}
int Count(int x){
    int re=1;
    for(int i=1;i<=m;i++)
        re=1ll*re*c[x][r[i]-1]%mod;
    return re;
}
signed main(){
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=m;i++)scanf("%d",u+i);
    for(int i=1;i<=m;i++)scanf("%d",r+i);
    Init();
    int ans=0,tmp,d=n-k-1;
    for(int i=0;i<=d;i++){
        int tmp=((d-i)&1)?mod-1:1;
        tmp=1ll*tmp*c[d][i]%mod;
        tmp=1ll*tmp*Count(i)%mod;
        ans=(ans+tmp)%mod;
    }
    for(int i=1,s;i<=m;i++){
        s=0;
        for(int t=0;t<r[i];t++){
            tmp=(t&1)?mod-1:1;
            tmp=1ll*tmp*Pow(u[i],r[i]-t-1)%mod;
            tmp=1ll*tmp*c[r[i]-1][t]%mod;
			tmp=1ll*tmp*Lagrange::Sum(u[i],n+t-r[i])%mod;
            s=(s+tmp)%mod;
        }
        ans=1ll*ans*s%mod;
    }
    ans=1ll*ans*c[n-1][k]%mod;
    printf("%d",ans);
    return 0;
}
posted @ 2019-05-06 22:32  The_KOG  阅读(218)  评论(0编辑  收藏  举报