(mathcal{Description})
给定坐标轴上的 (2n+1) 个坐标 (x_1,x_2,cdots,x_{2n+1}),其中偶数下标的位置是一个小球,奇数下标的位置是一个球洞。每次操作随机选择一个小球,并随机让它向左或向右滚入临近的球洞,该球洞被填满,视作平地。求所有球进洞后,球滚动总距离的期望。对 (998244353) 取模。
(nle3000)。
(mathcal{Solution})
显然,(n) 个球进洞的总方案为 (2^nn!),记为 (g(n))。现只需要计算所有方案的滚动距离之和。坐标实际位置并不重要,考虑一段形如 (x_ileftrightarrow x_{i+1}) 的距离在多少种方案中贡献。
贡献次数显然仅与 (n) 和位置 (i) 有关。令 (f(i,j)) 表示仅有 (i) 个球(和 (i+1) 个洞)时,(x_jleftrightarrow x_{j+1}) 的贡献次数。转移时,考虑当前局面第一次操作:
-
让 (x_j) 和 (x_{j+1}) 配对消失,贡献次数为剩下 (i-1) 个球撞完的总方案数,即 (g(n-1)),并且 (x_jleftrightarrow x_{j+1}) 这一段被纳入了(x_{j-1}leftrightarrow x_{j+2}),转移需要让坐标前移一位,那么 (f(i,j) leftarrow f(i,j)+g(i-1)+f(i-1,j-1))。
-
操作 (j) 前面的球,有 (j-1) 种等价操作方式,当前这段没有贡献,坐标向前两位,即 (f(i,j) leftarrow f(i,j)+(j-1)f(i-1,j-2))。
-
操作 (j+1) 后面的球,有 (2i-j) 种等价操作方式,当前这段还是没有贡献,坐标也没有影响,即 (f(i,j) leftarrow f(i,j)+(2i-j)f(i-1,j))。
综上:
答案显而易见:
复杂度 (mathcal O(n^2))。
(mathcal{Code})
/* Clearink */
#include <cstdio>
inline int rint () {
int x = 0, f = 1; char s = getchar ();
for ( ; s < '0' || '9' < s; s = getchar () ) f = s == '-' ? -f : f;
for ( ; '0' <= s && s <= '9'; s = getchar () ) x = x * 10 + ( s ^ '0' );
return x * f;
}
template<typename Tp>
inline void wint ( Tp x ) {
if ( x < 0 ) putchar ( '-' ), x = ~ x + 1;
if ( 9 < x ) wint ( x / 10 );
putchar ( x % 10 ^ '0' );
}
const int MAXN = 3000, MOD = 998244353;
int n, m, x[MAXN * 2 + 5], g[MAXN + 5], f[MAXN + 5][MAXN * 2 + 5];
inline int& addeq ( int& a, const int b ) {
return ( a += b ) < MOD ? a : a -= MOD;
}
inline int qkpow ( int a, int b, const int p = MOD ) {
int ret = 1;
for ( ; b; a = 1ll * a * a % p, b >>= 1 ) ret = 1ll * ret * ( b & 1 ? a : 1 ) % p;
return ret;
}
int main () {
// freopen ( "stars.in", "r", stdin );
// freopen ( "stars.out", "w", stdout );
m = ( n = rint () ) << 1 | 1;
for ( int i = 1; i <= m; ++ i ) x[i] = rint ();
g[0] = 1;
for ( int i = 1; i <= n; ++ i ) {
g[i] = 2ll * i * g[i - 1] % MOD;
for ( int j = 1; j <= i << 1; ++ j ) {
addeq ( addeq ( addeq ( addeq ( f[i][j], g[i - 1] ), f[i - 1][j - 1] ),
( j - 1ll ) * f[i - 1][j - 2 < 0 ? 0 : j - 2] % MOD ),
( 2ll * i - j ) * f[i - 1][j] % MOD
);
}
}
int ans = 0;
for ( int i = 1; i <= n << 1; ++ i ) {
addeq ( ans, 1ll * ( x[i + 1] - x[i] ) * f[n][i] % MOD );
}
wint ( 1ll * ans * qkpow ( g[n], MOD - 2 ) % MOD ), putchar ( '
' );
return 0;
}
(mathcal{Details})
考场上想的统计每一对 (i) 球撞 (j) 洞的出现次数,但这个涉及到多类方案的交叉安排,而且方案间有依赖关系……就死掉啦。
还有,暴力打半天过不了样例,手玩了一下发现距离贡献没乘方案数 qwq。