CF1096E The Top Scorer
题目传送门:CF1096E
洛谷入口
题目大意:
\(p个人,每个人有得分a_i\)
\(总得分∑a_i=s\)
\(第一个人得分a_1≥r\)
\(得分最高的人可以获胜,如果多个人得分最高,则等概率随机其中一个人获胜\)
\(问第一个人获胜的概率(运算皆对998244353取模)\)
数据范围
\(\circ\) \(1\le p\le100\)
\(\circ\) \(0\le r\le s\le5000\)
题解
这题算概率,就是获胜方案数除以总情况数
那要求获胜方案数就可以试着去\(DP\)
首先就先枚举获胜者的分数,假设为\(i\)
接下来再假设有\(j\)个人都是这个分数\(i\)(包含此获胜者)
那么剩余人还有\(p-j\)个
剩余分数还有\(s-i\times j\)
而且这些人分数都不到\(i\)
剩余的人分一些分简单,但如何让每个人得分都不超过\(i\)呢?
其实可以用容斥的思想做一下
我们先考虑至少\(0\)人超过要求的方案数
再减去至少\(1\)人的方案数
会发现减多了,于是再加回至少\(2\)人的方案数
…………………………
最后就加上\((-1)^i\times\)至少p-j人方案数
那对于至少\(x\)人,要求其超过\(lim-1\)的求法:
先给这\(x\)人每人分个\(lim\)的分数
然后再按照隔板法来分(要选其中元素可为\(0\)的方法)
这样就可以算出一个通式:
\((-1)^x\times C_p^x \times C^{p-1}_{s-lim\times x+p-1}\)
那\(i\)再按照\(0\)到\((p-j)\)枚举即可解决对于问题\(Q(总个数s,总人数p,限制lim)\)的方案数
那把这个套进去大的轮廓会得到答案求法:
\(\sum\limits^{s}_{i=r}\sum\limits^{p}_{j=1}Q(s-i\times j,p-j,i)\times C^{j-1}_{p-1}/j\)
其实理解到这,总情况求法肯定都没问题了吧
就是\(C^{p-1}_{s-r+p-1}\)
那么解题步骤就这些
式子没啥进一步推的,这个复杂度就可以过了
注意事项
建议把所有范围内的组合数都求一遍
①.组合数递推式是一个公式(其实可以用实际问题的方式轻松证明)
\(C^{j}_{i}=C^{j}_{i-1}+C^{j-1}_{i-1}\)
注意初始化\(C^0_i都为1\)
②.逆元的线性求法有一个公式
\(inv_i=mod-(mod/i)\times inv_{mod\%i}\%mod\)
初始化的话记得加个\(inv_1=1\)
③.最后除以总情况时最好用个费马小定理解决
(说到费马小定理就别忘了带上快速幂)
好了就这些了好像挺多的,下面上代码!↓↓↓
AC代码
#include<bits/stdc++.h>
#define maxn 5200
#define int long long//懒的表现
using namespace std;
int mod=998244353,inv[maxn],c[maxn+10][maxn+10],p,s,r,ans;//懒*2
void init(){//初始化inv&&c
inv[1]=1;
for(int i=2;i<=p;i++)inv[i]=mod-(mod/i)*inv[mod%i]%mod;
c[0][0]=1;
for(int i=1;i<=maxn;i++){
c[0][i]=1;
for(int j=1;j<=i;j++)c[j][i]=(c[j][i-1]+c[j-1][i-1])%mod;
}
}
int ksm(int x,int y){
int tot=1,tmp=x;
while(y){
if(y&1)tot=tot*tmp%mod;
tmp=tmp*tmp%mod;
y>>=1;
}
return tot;
}
int C(int a,int b){//为了谨慎而存在
if(a>b||a<0||b<0)return 0;
return c[a][b];
}
int jj(int sum,int x,int lim){
if(sum==0)return 1;
if(sum<0)return 0;
int tot=0;
for(int i=0;i<=x;i++)tot=(tot+((i&1)?998244352:1)*c[i][x]%mod*C(x-1,sum-i*lim+x-1))%mod;
return tot;
}
signed main(){
cin>>p>>s>>r;
init();
for(int i=r;i<=s;i++){
for(int j=1;j<=p;j++){
if((p-j)*(i-1)+i*j<s)continue;
ans=(ans+jj(s-i*j,p-j,i)*C(j-1,p-1)%mod*inv[j])%mod;
}
}
cout<<ans*ksm(c[p-1][s-r+p-1],mod-2)%mod;
}