1. 程式人生 > >CF1096E.The Top Scorer[概率期望]

CF1096E.The Top Scorer[概率期望]

\[\text{題意:有}n\text{個人,每人有一個分數}a_i\left( a_i\geq 0 \right) ,\sum{a_i}=s\]
\[\text{假設最高分有}x\text{個,}x\text{個人中的每個人都有}\frac{1}{x}\text{的概率獲勝}\]
\[\text{第1個人的得分一定在}\left[ r,s \right] \text{之內,給出}n,s,r\text{,求他的獲勝概率}\]
\[\text{用隔板法,有}\left( \begin{array}{c} s-r+n-1\\ n-1\\ \end{array} \right)\text{種方案}\left( \text{有}r\text{個球已經被固定分給第1個人了} \right)\]


\[\text{求出第1個人作為最高分有多少種方案,再除以總方案數就是獲勝概率(要除以同分人數)}\]
\[\text{列舉第1個人得了多少分}x\text{,以及跟他同分的人的個數}y\text{(不包括自己)}\]
\[\text{令}f\left( a,b,c \right) \text{表示}a\text{個非負整數的和是}b,\text{這}a\text{個數的上界是}c\text{的方案數}\]
\[\text{不考慮上界答案是}\left( \begin{array}{c} b+a-1\\ a-1\\ \end{array} \right) \text{(隔板法)}\]

\[g\left( i \right) \text{表示}\geq n-i\text{個不合法}\left( \leq i\text{個合法} \right) \text{的方案數,}h\left( i \right) \text{表示有}n-i\text{個不合法}\left( i\text{個合法} \right) \text{的方案數,}\]


\[g\left( x \right) =\sum_{i=0}^x{\left( \begin{array}{c} n\\ i\\ \end{array} \right) h\left( i \right)}\]
\[\text{要求}h\left( n \right) ,\text{由二項式反演}\]
\[h\left( n \right) =\sum_{i=0}^n{\left( -1 \right) ^{n-i}\left( \begin{array}{c} n\\ i\\ \end{array} \right) g\left( i \right)}\]

\[\text{對於一個}x\text{,}\sum_{y=0}^{n-1}{\left( \begin{array}{c} n-1\\ y\\ \end{array} \right) f\left( n-y-1,s-x\left( y+1 \right) ,x-1 \right)}\text{就是}x\text{作為最高分的方案數}\]

\[\text{所以答案就是}\frac{\sum_{x=r}^s{\begin{array}{c} \sum_{y=0}^{n-1}{\frac{\left( \begin{array}{c} n-1\\ y\\ \end{array} \right) f\left( n-y-1,s-x\left( y+1 \right) ,x-1 \right)}{\left( y+1 \right)}}\\ \end{array}}}{\left( \begin{array}{c} s-r+n-1\\ n-1\\ \end{array} \right)}\]

#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
inline int Pow(int x, int y) {
  int ret;
  for (ret = 1; y; y >>= 1, x = x * 1ll * x % mod) if (y & 1) ret = ret * 1ll * x % mod;
  return ret % mod;
}
struct Moder {
  int a;
  Moder(int a) : a(a) {}
  Moder() {}
  inline int inv() {return Pow(a, mod - 2);}
  inline void operator += (const int b) {a += b; if (a < 0) a += mod; else if (a >= mod) a -= mod;}
  inline void operator -= (const int b) {a -= b; if (a < 0) a += mod; else if (a >= mod) a -= mod;}
  inline void operator *= (const int b) {a = a * 1ll * b % mod; if (a < 0) a += mod;}
  inline void operator /= (const int b) {a = a * 1ll * Pow(b, mod - 2) % mod; if (a < 0) a += mod;}
  inline void operator += (const Moder &rhs) {*this += rhs.a;}
  inline void operator -= (const Moder &rhs) {*this -= rhs.a;}
  inline void operator *= (const Moder &rhs) {*this *= rhs.a;}
  inline void operator /= (const Moder &rhs) {*this /= rhs.a;}
  inline Moder operator + (const Moder &rhs) const {Moder c = *this; c += rhs; return c;}
  inline Moder operator - (const Moder &rhs) const {Moder c = *this; c -= rhs; return c;}
  inline Moder operator * (const Moder &rhs) const {Moder c = *this; c *= rhs; return c;}
  inline Moder operator / (const Moder &rhs) const {Moder c = *this; c /= rhs; return c;}
  inline void operator = (const int x) {a = x;}
  inline void operator = (const Moder &rhs) {a = rhs.a;}
} fac[10005], ifac[10005];
int n, s, r;
inline Moder C(int n, int m) {
  if (m > n || m < 0) return 0;
  return fac[n] * ifac[n - m] * ifac[m];
}
inline Moder F(int n, int m) {//n個非負整數的和是m的方案數
  if (m < 0) return 0;
  return C(n + m - 1, n - 1);
}

inline Moder F1(int n, int m, int r) { //n個非負整數的和是m 上界是r的方案數
  if (!n && !m) return Moder(1); //這裡是合法的,需要return 1
  Moder ret = 0, sign = (n & 1) ? -1 : 1;
  for (int i = 0; i <= n; ++i, sign = sign * -1) if (m - (r + 1) * (n - i) >= 0) ret = ret + sign * C(n, i) * F(n, m - (r + 1) * (n - i));
  // Moder ret = 0, sign = 1;
  // for (int i = 0; i <= n && m - (r + 1) * i >= 0; ++i, sign = sign * -1) ret = ret + sign * C(n, i) * F(n, m - (r + 1) * i);
  //容斥
  return ret;
}

int main() {
  fac[0] = 1;
  for (int i = 1; i <= 5100; ++i) fac[i] = fac[i - 1] * i;
  ifac[5100] = fac[5100].inv();
  for (int i = 5099; i >= 0; --i) ifac[i] = ifac[i + 1] * (i + 1);
  cin >> n >> s >> r;
  Moder ans = 0;
  for (int x = r; x <= s; ++x) {
    for (int y = 0; (y + 1) * x <= s && y + 1 <= n; ++y) {
      int m = n - y - 1, ss = s - (y + 1) * x;
      ans += F1(m, ss, x - 1) * C(n - 1, y) / (y + 1);
    }
  }
  ans /= C(s - r + n - 1, n - 1);
  cout << ans.a;
  return 0;
}