题解:P15111 群星

· · 题解

我觉得难点在 DP 啊。为啥题解叽里咕噜说一坨期望怎么算。

分析

设当前排名为 x,观察发生一场战争后排名的期望。

分情况讨论:

期望为:

\begin{aligned}\\ &\frac{\binom{n-1}{2}\cdot x + \sum\limits_{y\ne x}^{}y}{\binom{n}{2}}\\ &=\frac{\binom{n-1}{2}\cdot x + (\frac{n(n+1)}{2}-x)}{\binom{n}{2}}\\ &=\frac{\frac{(n-1)(n-2)}{2}\cdot x + \frac{n(n+1)}{2}-x}{\frac{n(n-1)}{2}}\\ &=(1-\frac{2}{n-1})\cdot x + (1+\frac{2}{n-1})\\ \end{aligned}

当 n \ge 3 时上面这个期望值随 x 增加单调不减。先不考虑 n < 3 的情况。

记 g(x,y) = (1-\frac{2}{n-1})\cdot g(x,y-1) + (1+\frac{2}{n-1})。

那么策略应该是在选择的时候直接选能选的中排名最小的那个。如果在世纪 i 能选择的最小排名为 x,那么答案就是 g(x,\sum\limits_{j\ge i}^{}a_j)。

记 f(x,c) 表示排名为 1\sim i 的文明中被选择的文明数量为 c 的概率。那么能选择的最小排名为 x 的概率就是 f(x-1,x-1)-f(x,x)。

定义状态函数 f_{i}(x,c) 为考虑到当前时刻,排名为 1\sim x 的文明中被选择的文明数量为 c 的概率。

世纪初,有:f_{i}(x,\min(c+1,x))=f_{i-1}(x,c)。

对于 f_i(x,c),可知排名 [1,x] 中有 c 个,[x+1,n] 中有 i-c 个。观察发生一场战争后的局面,分类讨论:

  1. 交换的文明对都不是被选择的文明。新状态为 (x,c)。概率 \frac{\binom{n-i}{2}}{\binom{n}{2}}。
  2. 交换的文明对恰有一个是被选择的文明。
    1. 被选择的文明在 [1,x],没被选择的文明在 [1,x]。新状态为 (x,c)。概率 \frac{c\cdot (x-c)}{ \binom{n}{2}}。
    2. 被选择的文明在 [1,x],没被选择的文明在 [x+1,n]。新状态 (x,c-1)。概率 \frac{c\cdot (n-x-(i-c))}{\binom{n}{2}}。
    3. 被选择的文明在 [x+1,n],没被选择的文明在 [1,x]。新状态 (x,c+1)。概率 \frac{(x-c)\cdot (i-c)}{\binom{n}{2}}。
    4. 被选择的文明在 [x+1,n],没被选择的文明在 [x+1,n]。新状态 (x,c)。概率 \frac{(i-c)\cdot (n-x-(i-c))}{\binom{n}{2}}。
  3. 交换的文明对都是被选择的文明。
    1. 都在 [1,x]。新状态 (x,c)。概率 \frac{\binom{c}{2}}{\binom{n}{2}}。
    2. 都在 [x+1,n]。新状态 (x,c)。概率 \frac{\binom{i-c}{2}}{\binom{n}{2}}。
    3. 一个在 [1,x],一个在 [x+1,n]。新状态 (x,c)。概率 \frac{c\cdot (i-c)}{\binom{n}{2}}。

整理一下,记转移前状态函数为 f'_i(x,c),转移后为 f_{i}(x,c)。有:

\begin{aligned}\\ f_{i}(x,c)&\gets f'_{i}(x,c)\cdot (\frac{\binom{n-i}{2}+c\cdot (x-c)+(i-c)\cdot (n-x-(i-c))+\binom{i}{2}}{\binom{n}{2}})\\ f_{i}(x,c-1)&\gets f'_{i}(x,c)\cdot (\frac{c\cdot (n-x-(i-c))}{\binom{n}{2}})\\ f_{i}(x,c+1)&\gets f'_{i}(x,c)\cdot(\frac{(x-c)\cdot (i-c)}{\binom{n}{2}}) \end{aligned}

发生 a_i 场战争就是转移 a_i 次。矩阵快速幂优化做到转移 O(n^4\log a_i)。

整体复杂度 O(kn^4\log \max(a_i)+kn\log(\sum a_i))。

不是,数据里怎么没有 n< 3 的情况啊。

$n = 2$ 的时候发生一场战争就一定会交换排名。对于 $i=1$ 答案一定是 $1$;对于 $i=2$ 在 $a_1\equiv a_2 \pmod 2$ 时为 $2$,否则为 $1$。 代码没判 $n < 3$。 ## 代码 ```cpp const int N = 55; const double eps = 1e-9; int n, k; int a[N], s[N]; struct Matrix{ int n, m; double c[N][N]; }; Matrix f[2][N], A, B, C; il Matrix mul(Matrix a, Matrix b){ Matrix c; c.n = a.n, c.m = b.m; U(i, 0, c.n) U(j, 0, c.m){ c.c[i][j] = 0; U(k, 0, a.m) c.c[i][j] += a.c[i][k] * b.c[k][j]; } return c; } il Matrix Qmi(Matrix a, int b){ Matrix res; res.n = a.n, res.m = a.m; U(i, 0, res.n) U(j, 0, res.n) res.c[i][j] = (i == j); while(b){ if(b & 1) res = mul(res, a); a = mul(a, a), b >>= 1; } return res; } il int C_2(int n){ return n * (n - 1) / 2; } il void solve(){ n = rd, k = rd; U(i, 1, k) a[i] = rd; D(i, k, 1) s[i] = s[i + 1] + a[i]; int I = 0; U(x, 0, n){ f[I][x].n = 0, f[I][x].m = x; f[I][x].c[0][0] = 1; } { B.n = 1, B.m = 1; B.c[0][0] = 1 - 2 * 1.0 / (n - 1); B.c[0][1] = 0; B.c[1][0] = 1.0; B.c[1][1] = 1.0; } U(i, 1, k){ double res = 0.0; U(x, 1, n){ double F = f[I][x - 1].c[0][x - 1] - f[I][x].c[0][x]; if(F < eps) continue; C.n = 0, C.m = 1; C.c[0][0] = x, C.c[0][1] = 1 + 2 * 1.0 / (n - 1); C = mul(C, Qmi(B, s[i])); res += C.c[0][0] * F; } printf("%.10lf\n", res); I ^= 1; U(x, 0, n){ f[I][x].n = 0, f[I][x].m = x; U(c, 0, x) f[I][x].c[0][c] = 0; } U(x, 0, n){ A.n = x, A.m = x; U(a, 0, x) U(b, 0, x) A.c[a][b] = 0; U(c, max(0ll, i - (n - x)), min(i, x)){ double v1 = (C_2(n - i) + c * (x - c) + (i - c) * (n - x - (i - c)) + C_2(i)) * 1.0 / C_2(n); double v2 = (c * (n - x - (i - c))) * 1.0/ C_2(n); double v3 = ((x - c) * (i - c)) * 1.0 / C_2(n); A.c[c][c] += v1; if(c >= 1) A.c[c][c - 1] += v2; if(c <= x - 1) A.c[c][c + 1] += v3; } A = Qmi(A, a[i]); U(c, 0, x) f[I][x].c[0][min(c + 1, x)] += f[I ^ 1][x].c[0][c]; f[I][x] = mul(f[I][x], A); } } return ; } ```