CF1096E The Top Scorer

Link
枚举自己的分数(i),再枚举有多少人(j)的分数是(i),那么答案就是(sumlimits_{i=r}^ssumlimits_{j=1}^pfrac{f(s-ij,p-j,i){p-1choose j-1}}j),其中(f(n,m,l))是指把(n)个球放进(m)个盒子,每个盒子中的球数必须(<l)的方案数。
容斥+隔板法得到(f(n,m,l)=sumlimits_{i=0}^m(-1)^i{mchoose i}{n-il+m-1choose 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)));
}
原文地址:https://www.cnblogs.com/cjoierShiina-Mashiro/p/12244601.html