CF1096E The Top Scorer

Link
枚举自己的分数\(i\),再枚举有多少人\(j\)的分数是\(i\),那么答案就是\(\sum\limits_{i=r}^s\sum\limits_{j=1}^p\frac{f(s-ij,p-j,i){p-1\choose j-1}}j\),其中\(f(n,m,l)\)是指把\(n\)个球放进\(m\)个盒子,每个盒子中的球数必须\(<l\)的方案数。
容斥+隔板法得到\(f(n,m,l)=\sum\limits_{i=0}^m(-1)^i{m\choose i}{n-il+m-1\choose m-1}\)。注意要先判断\(f(n,m,l)=0\)的情况。

#include<cstdio>
const int N=5107,P=998244353;
int r,p,s,c[N][N],inv[107];
int mod(int x){return x+(x>>31&P);}
int inc(int a,int b){return mod(a+b-P);}
int dec(int a,int b){return mod(a-b);}
int mul(int a,int b){return 1ll*a*b%P;}
int pow(int a,int k){int r=1;for(;k;k>>=1,a=mul(a,a))if(k&1)r=mul(a,r);return r;}
int C(int n,int m){return n<0||m<0||n<m? 0:c[n][m];}
int f(int n,int m,int l)
{
    if(!n) return 1;
    int ans=0;
    for(int i=0;i<=m;++i) ans=(i&1? dec:inc)(ans,mul(C(m,i),C(n-i*l+m-1,m-1)));
    return ans;
}
int main()
{
    inv[0]=inv[1]=1,scanf("%d%d%d",&p,&s,&r);int ans=0;
    for(int i=0,j;i<=5100;++i)for(c[i][0]=j=1;j<=i;++j)c[i][j]=inc(c[i-1][j],c[i-1][j-1]);
    for(int i=2;i<=100;++i)inv[i]=mul(inv[P%i],P-P/i);
    for(int i=r;i<=s;++i) for(int j=1;j<=p&&j*i<=s;++j) if(p*i-p+j>=s) ans=inc(ans,mul(mul(inv[j],C(p-1,j-1)),f(s-i*j,p-j,i)));
    printf("%d",mul(ans,pow(C(s-r+p-1,p-1),P-2)));
}
posted @ 2020-01-31 08:44  Shiina_Mashiro  阅读(121)  评论(0编辑  收藏  举报