题解:P10868 [HBCPC2024] Points on the Number Axis B
节选自:DP做题记录(三)(2025.4.5 - 2025.4.19)
我们先从简单的情况考虑,如果只有两个点 \(x_1\) 和 \(x_2\),那么中点一定是 \(\displaystyle\frac{x_1}{2} + \frac{x_2}{2}\),如果有三个点 \(x_1, x_2, x_3\),那么第一次分两种情况:
-
先合并 \(x_1, x_2\),变成 \(\displaystyle\frac{x_1}{2} + \frac{x_2}{2}\),再合并 \(x_3\),变成 \(\displaystyle\frac{x_1}{4} + \frac{x_2}{4} + \frac{x_3}{2}\);
-
先合并 \(x_2, x_3\),变成 \(\displaystyle\frac{x_2}{2} + \frac{x_3}{2}\),再合并 \(x_1\),变成 \(\displaystyle\frac{x_1}{2} + \frac{x_2}{4} + \frac{x_3}{4}\)。
因此期望就是 \(\displaystyle\frac 12 \times (\frac{x_1}{4} + \frac{x_2}{4} + \frac{x_3}{2}) + \frac 12 \times (\frac{x_1}{2} + \frac{x_2}{4} + \frac{x_3}{4}) = \frac 38 x_1 + \frac 14 x_2 + \frac 38 x_3\)。
其实可以发现,最后的式子一定可以表示成 \(\displaystyle\sum w_k x_k\),可以感性理解一下,每次求中点时,都把两边已经得到的式子乘了一个 \(\displaystyle\frac 12\),这并不会改变式子的次数,只会改变式子的系数,因此我们现在需要求出所有的 \(w_i\)。
设 \(dp_{i, j}\) 表示当前枚举的点(可能是合并出来的)左边还剩 \(i\) 个点,右边还剩 \(j\) 个点,中间这个点系数的期望。考虑本次合并,如果是将左边 \(i\) 个点中任意两个点合并(一共 \(i - 1\) 中合并方法),对当前枚举的这个点的系数没有影响,因此 \(dp_{i, j}\) 首先要加上 \(\displaystyle\frac{i - 1}{i + j}dp_{i - 1, j}\)(系数表示从 \(i + j\) 个可合并位置中选出 \(i - 1\) 个位置的概率),同理,\(dp_{i, j}\) 也要加上 \(\displaystyle\frac{j - 1}{i + j} dp_{i, j - 1}\)。
现在来考虑将枚举到的这个点合并进来,此时就要乘以系数 \(\displaystyle\frac 12\),于是 \(dp_{i, j}\) 还要加上 \(\displaystyle\frac 12 \times \frac{1}{i + j} \times (dp_{i - 1, j} + dp_{i, j - 1})\),因此最终的转移方程就是 \(dp_{i, j} = \displaystyle\frac{i - 1}{i + j} dp_{i - 1, j} + \frac 12 \frac {1}{i + j} dp_{i - 1,j} + \frac 12 \frac{1}{i + j} dp_{i, j - 1} + \frac{j - 1}{i + j} dp_{i, j - 1}\)。一个点的贡献就是 \(\displaystyle\sum dp_{i - 1, n - i} x_i\)
我们现在考虑优化,首先一个优化方式就是将期望改写成总和除以总方案数,那么就可以将转移方程改写为 \(dp_{i, j} = \displaystyle\frac{1}{(n - 1)!} [(i - \frac 12) dp_{i - 1, j} + (j - \frac 12) dp_{i, j - 1}]\)。
现在就到了要充分发扬类人智慧的时候了,考虑 \(dp\) 式子的组合含义(其实也可以直接矩乘加特征向量做,不过特别难算),那就相当于从 \((i, j)\) 这个点走到 \((0, 0)\),往上走需要花费 \(i - \displaystyle\frac 12\) 的代价,往左走需要花费 \(j - \displaystyle\frac 12\) 的代价,所有路径的代价和。那么我们一定走了 \(i + j\) 步,其中 \(i\) 步向上可以随时走,因此 \(dp_{i, j} = \displaystyle\binom{i + j}{i} (i - \frac 12)^{\underline{i - 1}} (j - \frac 12)^{\underline{j - 1}}\)。此时我们只需要预处理一下就可以 \(O(n)\) 通过此题了。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e6 + 9, MOD = 998244353;
int x[N], fac[N], inv[N], des[N], c, n, ans;
int qpow(int a, int b){
int res = 1;
while(b > 0){
if(b & 1)
res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
signed main(){
scanf("%lld", &n);
for(int i = 1; i <= n; i++)
scanf("%lld", &x[i]);
c = qpow(2, MOD - 2);
fac[0] = 1;
for(int i = 1; i <= n; i++)
fac[i] = fac[i - 1] * i % MOD;
inv[n] = qpow(fac[n], MOD - 2);
for(int i = n - 1; i >= 0; i--)
inv[i] = inv[i + 1] * (i + 1) % MOD;
des[0] = 1;
for(int i = 1; i <= n; i++)
des[i] = (i - c + MOD) % MOD * des[i - 1] % MOD;
for(int i = 1; i <= n; i++)
ans = (ans + x[i] * des[i - 1] % MOD * des[n - i] % MOD * inv[i - 1] % MOD * inv[n - i] % MOD) % MOD;
printf("%lld", ans);
return 0;
}
本文来自博客园,作者:Orange_new,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18841171