1. 程式人生 > 實用技巧 >CF1096E The Top Scorer 題解

CF1096E The Top Scorer 題解

CF1096E The Top Scorer

題意

\(~~~~\) 給出數列 \(p\) 個人各自的 \(a_i\) 表示得分, \(\sum a_i=s\) ,求在第一個數 \(\geqslant r\) 的情況下,它是最大值的概率。若有其他數與它的值相同,最大值會認為是等概率選擇了其中的一個.(即若不包括它在內有 \(k\) 個最大值,則概率 \(/k\)


題解

\(~~~~\) \(~~~~\) 不會吧不會吧,這題CF上只有2500。受到專題訓練影響直接想 \(\texttt{DP}\) ,然後發現時空都會爆,狀態具體怎麼定義出來都成問題。

\(~~~~\) 否決了概率 \(\texttt{DP}\)

,那現在我們只能直接計算概率了。

\(~~~~\) 總的方案數很好求,是:

\[\Large \begin{pmatrix} s-r+n-1\\ n-1 \end{pmatrix} \]

\(~~~~\) 解釋: 上式可以用插板法可以推出,相當於把 \(s-r\) 分(第一個人必須有 \(r\))分配給 \(p\) 個人。但注意分數可以是 \(0\) ,所以每個人插板後會有新空隙。

\(~~~~\) 所以我們來求合法的方案數。

\(~~~~\) 列舉有 \(i\) 人(包括 \(1\) 自己在內)同最高分 \(x\) 。那我們有 \(\begin{pmatrix}p-1\\i-1\end{pmatrix}\)

\(1\) 必定要被選)種選人方案。

\(~~~~\) 接下來是求另一個子問題: \(p-i\) 人分 \(s-ix\) 分,每人可以分到 \([0,x-1]\) 分的方案數。

\(~~~~\) 為方便,下文令:\(n=s-ix,m=p-i\).

\(~~~~\) 方案數無法直接正面求到,那我們是否可以考慮反面求呢?

\(~~~~\) 考慮優先給 \(m\) 個人都安排上 \(x\) 分,那這樣就可以求出 \(m\) 個人都不滿足條件的方案數。以此類推算出\([0,m-1]\) 時的方案數\(\dots\dots\)了嗎?

\(~~~~\) 並不是的,我們發現在求 \(m-1\) 人不合法時,是包括 \(m\)

人合法的情況的,也就是說我們每次求出來的應該是:至少 \(k\) 個人不合法的方案數。

\(~~~~\) 等等,提到了至少?那我們就自然而然想到容斥了。

\(~~~~\) 考慮當至少\(k\in[0,m]\) 人不合法時的方案數:

  • 有容斥係數:\((-1)^k\times\begin{pmatrix}m\\k\end{pmatrix}\) ;
  • 綜合之前的策略,有答案:\(\begin{pmatrix}n-kx+m-k-1\\k\end{pmatrix}\) .

\(~~~~\) 因此這個子問題的答案是:

\[\Large \sum_{k=0}^{m} (-1)^k\times \begin{pmatrix}m\\k\end{pmatrix}\times \begin{pmatrix}n-kx+m-k-1\\k\end{pmatrix} \]

\(~~~~\) 綜上,總的答案就是:

\[\Large \sum_{x=r}^{s}\sum_{i=1}^{p} \begin{pmatrix}p\\i\end{pmatrix}\times (\sum_{k=0}^{m} (-1)^k\times \begin{pmatrix}m\\k\end{pmatrix}\times \begin{pmatrix}n-kx+m-k-1\\k\end{pmatrix}) \]

\(~~~~\) 但這只是算到了合法方案數,而當 \(i\) 人同分時,概率會變為原式的 \(\dfrac{1}{i}\) ,因此在求答案時要在上式每次 \(\times \dfrac{1}{i}\) .

\(~~~~\) 此外還要注意當 \(i=p\) 時需要特判 \(ix=s\) 是否成立,否的話答案為 \(0\) ,否則答案為 \(1\) (記得這是方案數,最後還是要 \(\times \dfrac{1}{i}\))

\(~~~~\) 最後除以總方案數就是概率了。

\(~~~~\) 另外算一下 \((n-kx+m-k-1)_{max}\) 就會發現組合數底數要遞推到 \(5099\) 而不是 \(5000\).


程式碼

(由於改組合數範圍的時候修改借鑑了神兔的程式碼,所以可能會有億點點像)

#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const ll MOD=998244353;
ll C[5105][5105];//C[i][j]:j選i
ll p,s,r;
inline ll qpow(ll a,ll b)
{
	ll ret=1;
	while(b)
	{
		if(b&1) ret=ret*a%MOD;
		b>>=1;
		a=a*a%MOD;
	}
	return ret;
}
ll calc(ll n,ll m,ll x)//子問題求解
{
	ll ret=0;
	for(ll k=0;k<=m&&x*k<=n;k++)
	{
		ll tmp=C[k][m]*C[m-1][n+m-1-k*x]%MOD;
		ret+=(k&1)?-tmp:tmp;
	}
	return ((ret%MOD)+MOD)%MOD;
}
int main() {
	C[0][0]=1;
	for(ll i=1;i<=5100;i++) 
	{
		C[i][i]=C[0][i]=1;
		for(ll j=1;j<=i;j++) C[j][i]=(C[j-1][i-1]+C[j][i-1])%MOD;	
	}
	ll ans=0;
	scanf("%lld %lld %lld",&p,&s,&r);
	for(ll x=r;x<=s;x++)
	{
		for(ll i=1;i<=p;i++)
		{
			if(i==p) (ans+=(i*x==s?qpow(i,MOD-2):0))%=MOD;//特判 i=p
			else (ans+=(C[i-1][p-1]*calc(s-i*x,p-i,x)%MOD*qpow(i,MOD-2)%MOD))%=MOD;
		}
	}
	printf("%lld",ans*qpow(C[p-1][s-r+p-1],MOD-2)%MOD);
	return 0;
}