Serval and Bonus Problem - 洛谷 
最近有 $\tt ARC\ F$ 题竟然是相似题,好吧其实也没有那么相似,但是第一步转换是经典的。
 
首先根据期望线性,求一条线段的期望就是求区间内所有点的期望的和。
之后考虑既然是点那问题就简单了,直接考虑每条线段的相对位置就行了,也就是考虑 $(2n + 1)$ 个点,随机排列被钦定的点 $X$ 被 $\tt K$ 条线段覆盖的期望。
直接考虑进行 $\tt Dp$,考虑去对点进行匹配,设考虑到第 $i$ 个点,还有 $j$ 个点没有右端点,当前位置有没有被选择的方案数。
$$ \begin{aligned} f(i, j, k) &\to f(i + 1, j + 1, k) \\ f(i, j, k) \times j &\to f(i + 1, j - 1, k) \\ f(i, j, 0) &\to f(i + 1, j, 1), j \ge K \end{aligned} $$
当然我们最后的时候还要考虑线段的顺序,点的顺序,两个端点的顺序,还要把之前是考虑长度为 $1$ 现在变成 $l$ 了。
我们可以发现两个点重合的概率是趋近于 $0$ 的。
 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include  <bits/stdc++.h>  using  namespace  std;namespace  Legendgod {	namespace  Read { 		#ifdef  Fread  		const  int  Siz = (1  << 21 ) + 5 ; 		char  *iS, *iT, buf[Siz]; 		#define  gc() ( iS == iT ? (iT = (iS = buf) + fread(buf, 1, Siz, stdin), iS == iT ? EOF : *iS ++) : *iS ++ )  		#define  getchar gc  		#endif   		template  <typename  T> 		void  r1 (T &x)   { 		    x = 0 ; 			char  c (getchar())  ; 			int  f (1 )  ; 			for (; !isdigit (c); c = getchar ()) if (c == '-' ) f = -1 ; 			for (; isdigit (c); c = getchar ()) x = (x << 1 ) + (x << 3 ) + (c ^ 48 ); 			x *= f; 		} 		template  <typename  T, typename ...Args> 		void  r1 (T &x, Args&...arg)   { 			r1 (x), r1 (arg...); 		} 		#undef  getchar  	} using  namespace  Read;const  int  maxn = 2e3  + 5 ;constexpr  int  mod = 998244353 ;int  n, L, K;int  fac[maxn << 1 ];int  ksm (int  x,int  mi)   {    int  res (1 )  ;     while (mi) {         if (mi & 1 ) res = 1ll  * res * x % mod;         mi >>= 1 ;         x = 1ll  * x * x % mod;     }     return  res; } int  Inv (int  x)   { return  ksm (x, mod - 2 ); }int  f[maxn << 1 ][maxn][2 ];void  Add (int  &x,int  c)   {    x = (x + c) % mod; } signed  main ()   {	int  i, j;     r1 (n, K, L);     f[0 ][0 ][0 ] = 1 ;     for (i = 0 ; i <= 2  * n + 1 ; ++ i) {         for (j = 0 ; j <= min (n, i); ++ j) {             for (int  k = 0 ; k <= 1 ; ++ k) {                 Add (f[i + 1 ][j + 1 ][k], f[i][j][k]);                 if (j > 0 ) Add (f[i + 1 ][j - 1 ][k], 1ll  * f[i][j][k] * j % mod);                 if (k == 0  && j >= K) Add (f[i + 1 ][j][1 ], f[i][j][0 ]);             }         }     }     fac[0 ] = 1 ;     for (i = 1 ; i <= 2  * n + 1 ; ++ i) fac[i] = 1ll  * fac[i - 1 ] * i % mod;     int  ans = 1ll  * Inv (fac[2  * n + 1 ]) * ksm (2 , n) % mod * L % mod * f[2  * n + 1 ][0 ][1 ] % mod * fac[n] % mod;     printf ("%d\n" , ans); 	return  0 ; } } signed  main ()   { return  Legendgod::main (), 0 ; }
 
当然你会发现这个题目被加强了,如果说 $O(n ^ 2)$ 是不能过的呢?
但是很遗憾,你是不能再对 $\tt Dp$ 进行优化了,因为状态数已经过大了。
我们考虑使用一些更加数学的方法,我们还是考虑区间为 $[0, 1]$ 的情况,对于每个点求概率(期望)。
$$ \begin{aligned} p_x = \sum_{i = k} ^ n \binom{n}{i} (2x(1 - x)) ^ i\times (1 - (2x(1 - x))^i \end{aligned} $$
其中 $x$ 表示点的位置,后面就是考虑线段的情况。
$$ \begin{aligned} &\int_{0}^1 p_x dx\\ =& \int_{0}^ 1 \sum_{i = k} ^ n \binom{n}{i} (2x(1 - x)) ^ i\times (1 - (2x(1 - x))^i\\ =& \sum_{i = k} ^ n \binom{n}{i} \int_{0}^1 (2x(1 - x)) ^ i \times (1 - (2x(1-x)))^{n - i}dx\\ =& \sum_{i = k} ^ n \binom{n}{i} \sum_{j = 0} ^ {n - i} (-1)^j \binom{n - i}{j} 2^{i + j} B(i + j + 1, i + j + 1)\\ \end{aligned} $$
其中 $B(x, y) = \frac{(x-1)!(y-1)!}{(x + y - 1)!}$。
考虑对于前面的东西进行变化,可以发现 $\binom{n}{i}\binom{n-i}{j} = \binom{n}{i+j}\binom{i+j}{j}$。
可以枚举 $i + j$。
$$ \begin{aligned} \sum_{i = k} ^ n \binom{n}{i} 2^i B(i + 1, i + 1)  \sum_{j = 0} ^ {i - k} (-1)^j\binom{i}{j} \end{aligned} $$
众所周知后面的东西只变化了下指标,我们是可以直接进行求和的。
可以得到 $\sum_{j = 0} ^ {i - k} (-1)^j \binom{i}{j} = (-1)^{i - k} \binom{i - 1}{i - k}$。
二项式拆开来就行了。
 
最终得到的答案是可以 $O(n)$ 计算的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 #include  <bits/stdc++.h>  using  namespace  std;namespace  Legendgod {	namespace  Read { 		#ifdef  Fread  		const  int  Siz = (1  << 21 ) + 5 ; 		char  *iS, *iT, buf[Siz]; 		#define  gc() ( iS == iT ? (iT = (iS = buf) + fread(buf, 1, Siz, stdin), iS == iT ? EOF : *iS ++) : *iS ++ )  		#define  getchar gc  		#endif   		template  <typename  T> 		void  r1 (T &x)   { 		    x = 0 ; 			char  c (getchar())  ; 			int  f (1 )  ; 			for (; !isdigit (c); c = getchar ()) if (c == '-' ) f = -1 ; 			for (; isdigit (c); c = getchar ()) x = (x << 1 ) + (x << 3 ) + (c ^ 48 ); 			x *= f; 		} 		template  <typename  T, typename ...Args> 		void  r1 (T &x, Args&...arg)   { 			r1 (x), r1 (arg...); 		} 		#undef  getchar  	} using  namespace  Read;const  int  maxn = 1e6  + 5 ;constexpr  int  mod = 998244353 ;int  n, L, K;int  fac[maxn], finv[maxn], pw2[maxn];int  ksm (int  x,int  mi)   {    int  res (1 )  ;     while (mi) {         if (mi & 1 ) res = 1ll  * res * x % mod;         mi >>= 1 ;         x = 1ll  * x * x % mod;     }     return  res; } void  init (int  x)   {    fac[0 ] = pw2[0 ] = 1 ;     for (int  i = 1 ; i <= x; ++ i) fac[i] = 1ll  * fac[i - 1 ] * i % mod;     finv[x] = ksm (fac[x], mod - 2 );     for (int  i = x - 1 ; i >= 0 ; -- i) finv[i] = 1ll  * finv[i + 1 ] * (i + 1 ) % mod;     for (int  i = 1 ; i <= x; ++ i) pw2[i] = 2ll  * pw2[i - 1 ] % mod; } int  C (int  a,int  b)   {    if (a < b || a < 0  || b < 0 ) return  0 ;     return  1ll  * fac[a] * finv[b] % mod * finv[a - b] % mod; } int  B (int  a,int  b)   {    if (a < 0  || b < 0 ) return  0 ;     return  1ll  * fac[a - 1 ] * fac[b - 1 ] % mod * finv[a + b - 1 ] % mod; } signed  main ()   {	int  i, j;     init (maxn - 5 );     r1 (n, K, L);     int  ans (0 )  ;     for (i = K; i <= n; ++ i) {         int  op = ((i - K) & 1 ) ? mod - 1  : 1 ;         ans = (ans + 1ll  * C (n, i) * pw2[i] % mod * B (i + 1 , i + 1 ) % mod * op % mod * C (i - 1 , i - K) % mod) % mod;     }     ans = 1ll  * ans * L % mod;     printf ("%d\n" , ans); 	return  0 ; } } signed  main ()   { return  Legendgod::main (), 0 ; }