题目大意
小明在打比赛,包括小明自己一共有 (p) 名选手参赛,每个人的得分是一个非负整数。最后的冠军是得分最高的人,如果得分最高的人有多个,就等概率从这些人中选一个当冠军。
现在小明已知了自己的得分大于等于 (r),所有选手的得分和为 (s)。求小明获胜的概率,结果对 (998244353) 取模。
(Solution:)
我们只需要保证小明为(TopScorer)即可,即保证剩下的人的分数都(leq)小明的分数,(ans)即为小明为(TopScorer)的方案数除以总方案数
因为这是DP专题里面的题,我们令(f_{s,p,m})表示(p)名选手总得分为(s),每名选手分数不超过(m)的方案数,显然有:
(f_{s,p,m}=sumlimits_{i=0}^{m}{f_{s-i,p-1,m}}),可以维护一个前缀和,但是这是(O(srp))的,显然(TLE)
但是这启发我们我们可以考虑单独计算某个(dp)值(答案用到的(dp)状态不多)为什么我就没有被启发到
那么(f_{s,p,m}=sumlimits_{i=0}^{p}{(-1)^{i} imes C_p^i imes C_{s+p-1-i(m+1)}^{p-1}})
问题来了,如何理解这个式子?(天知道我为了理解它花了多长时间)
第一种理解方式:容斥
遇到有关最大值的问题,可以转化为“不超过”
在此题中,即为其他人的分数都不超过小明的分数
即计算所有情况-至少一个人超过(m+)至少两个人超过(m-)至少三个人超过(m)(+...)(奇加偶减),所以容斥系数即为((-1)^i)
再考虑(C_p^i imes C_{s+p-1-i(m+1)}^{p-1}),首先在(p)个人中选出(i)个人,即为(C_p^i),再给每个人分配((m+1))的分数(意思即保证这些人的分数都大于(m)),然后就是允许有空盒子的隔板法了
第二种理解方式:二项式反演
二项式反演就是这样的很对称一个式子:
(f_{n}=sum_{i=0}^{n}(-1)^{i} imes C_{n}^{i} imes g_{i} Longleftrightarrow g_{n}=sum_{i=0}^{n}(-1)^{i} imes C_{n}^{i} imes f_{i})
一个很对称的常见表达为:(f_{n}=sum_{i=0}^{n} C_{n}^{i} imes g_{i} Longleftrightarrow g_{n}=sum_{i=0}^{n}(-1)^{n-i} imes C_{n}^{i} imes f_{i})
具体证明可以看看这篇博客
那么我们把它套到我们的式子中,设(A(x))表示(leq x)个人不超过(m)的方案数,(B(x))表示恰好有(x)个人不超过(m)的方案数,显然有:
(A(n)=sumlimits_{i=0}^nC_n^i imes B(i)),由二项式反演:
(B(n)=sumlimits_{i=0}^{n}{(-1)^{n-i} imes C_n^i imes A(i)}),将 (i) 全部换成 (n-i)(这么换相当于把原来的正序(sum)改成了倒序,不会影响答案),有:
(B(n)=sumlimits_{i=0}^{n}{(-1)^{i} imes C_n^i imes A(n-i)}),(其中 (C_{n}^{n-i}=C_{n}^i),所以不变)因为有(n-i)个人不超过(m) (Longleftrightarrow) 有(i)个人超过(m),那么给每个人分配(m+1)分,再使用隔板法,有:
(B(p)=sumlimits_{i=0}^{p}{(-1)^i imes C_p^i imes C_{s+p-1-i(m+1)}^{p-1}}),这样就得到了同样的结论
回归正题,我们得到了(f_{s,p,m})的表达式后,我们尝试用它来表示(answer),那么:
问题又双叒叕来了,如何解释这个式子?
外层循环(t)枚举的是小明的分数,即所有人的分数(leq t);
(q)枚举的是有多少同分的最高分,(C_{p-1}^{q-1}) 描述的是从(p-1)个人((-1)意即除去小明)中选出 (q-1)个人,(frac{1}{q})即题目中同分的人均分成为(TopScorer)的概率;
(f_{s-qt, p-q, t-1})描述的是除去最高分的人,剩下的方案数;
最后分母 (C_{s-r+p-1}^{p-1}) 描述的是总的方案数。
呼~终于讲完了,上代码
(Code:)
#include<bits/stdc++.h>
using namespace std;
namespace my_std
{
typedef long long ll;
typedef double db;
#define pf printf
#define pc putchar
#define fr(i,x,y) for(register ll i=(x);i<=(y);i++)
#define pfr(i,x,y) for(register ll i=(x);i>=(y);i--)
#define go(x) for(ll i=head[u];i;i=e[i].nxt)
#define enter pc('
')
#define space pc(' ')
#define fir first
#define sec second
#define MP make_pair
const ll inf=0x3f3f3f3f;
const ll inff=1e15;
inline ll read()
{
ll sum=0,f=1;
char ch=0;
while(!isdigit(ch))
{
if(ch=='-') f=-1;
ch=getchar();
}
while(isdigit(ch))
{
sum=(sum<<1)+(sum<<3)+(ch^48);
ch=getchar();
}
return sum*f;
}
inline void write(ll x)
{
if(x<0)
{
x=-x;
pc('-');
}
if(x>9) write(x/10);
pc(x%10+'0');
}
inline void writeln(ll x)
{
write(x);
enter;
}
inline void writesp(ll x)
{
write(x);
space;
}
}
using namespace my_std;
const ll N=5500,mod=998244353;
ll p,r,s,mul[N],inv[N],c[N][N],ans;
inline ll ksmod(ll a,ll b)
{
ll ans=1;
while(b)
{
if(b&1)
{
ans=(ans*a)%mod;
}
a=(a*a)%mod;
b>>=1;
}
return ans;
}
inline ll C(ll n,ll m)
{
if(m>n||m<0||n<0) return 0;
ll res=inv[m]*inv[n-m]%mod;
res=res*mul[n]%mod;
return res;
}
inline void init()
{
mul[0]=inv[0]=1;
for(ll i=1;i<=p+s;i++) mul[i]=(mul[i-1]*i)%mod;
inv[p+s]=ksmod(mul[p+s],mod-2);
for(ll i=p+s-1;i;i--) inv[i]=inv[i+1]*(i+1)%mod;
}
inline ll f(ll s,ll p,ll m)
{
if(s==0&&p==0) return 1;
ll ans=0,tmp=1;
fr(i,0,p)
{
if(s+p-1-i*(m+1)<0) break;
ans=(ans+tmp*C(p,i)%mod*C(s+p-1-i*(m+1),p-1)%mod+mod)%mod;
tmp*=-1;
}
return ans;
}
int main(void)
{
p=read(),s=read(),r=read();
init();
fr(t,r,s) fr(q,1,p) ans=(ans+(C(p-1,q-1)*ksmod(q,mod-2))%mod*f(s-q*t,p-q,t-1))%mod;
ans=(ans*ksmod(C(s-r+p-1,p-1),mod-2))%mod;
writeln(ans);
return 0;
}