题解:P15111 群星
harmis_yz
·
2026-11-09 10:48:07
·
题解
我觉得难点在 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 个。观察发生一场战争后的局面,分类讨论:
交换的文明对都不是被选择的文明。新状态为 (x,c) 。概率 \frac{\binom{n-i}{2}}{\binom{n}{2}} 。
交换的文明对恰有一个是被选择的文明。
被选择的文明在 [1,x] ,没被选择的文明在 [1,x] 。新状态为 (x,c) 。概率 \frac{c\cdot (x-c)}{ \binom{n}{2}} 。
被选择的文明在 [1,x] ,没被选择的文明在 [x+1,n] 。新状态 (x,c-1) 。概率 \frac{c\cdot (n-x-(i-c))}{\binom{n}{2}} 。
被选择的文明在 [x+1,n] ,没被选择的文明在 [1,x] 。新状态 (x,c+1) 。概率 \frac{(x-c)\cdot (i-c)}{\binom{n}{2}} 。
被选择的文明在 [x+1,n] ,没被选择的文明在 [x+1,n] 。新状态 (x,c) 。概率 \frac{(i-c)\cdot (n-x-(i-c))}{\binom{n}{2}} 。
交换的文明对都是被选择的文明。
都在 [1,x] 。新状态 (x,c) 。概率 \frac{\binom{c}{2}}{\binom{n}{2}} 。
都在 [x+1,n] 。新状态 (x,c) 。概率 \frac{\binom{i-c}{2}}{\binom{n}{2}} 。
一个在 [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 ;
}
```