洛谷P8967 追寻 | Pursuit of Dream 题解
题目链接:P8967 追寻 | Pursuit of Dream
题意:
在 $n$ 维空间中有一个梦想。这梦想坐落在 $(d_1, d_2, \ldots, d_n)$ 的地方。而你从 $(0, 0, \ldots, 0)$ 开始,开启寻梦的旅程。
你的步伐轻缓,每一步只能走一个单位长度。你并不知道你的梦想位于哪里,所以你只能随机选择 $n$ 个正方向中的一个,然后向这个方向走一步。也就是说,在 $[1, n]$ 中均匀随机选择一个正整数 $h$,然后,使你在第 $h$ 维的坐标变成原来的坐标加一。
然而,天有不测风云。在你走每一步的过程中,你会有 $p = \sum_{i = 1}^k p_i$ 的概率散入天际,并开始一段新的旅程。你会在 $k$ 个地点中的一个重新开始这段旅程,其中第 $i$ 个地点的坐标是 $(a_{i,1}, a_{i,2}, \ldots, a_{i,n})$,从这里重新开始的概率为 $p_i$。
那么,期望下,你离到达这个梦想还需要多少步呢?
输入格式:
第一行,两个正整数 $n,k$。
第二行,$n$ 个非负整数 $d_1, d_2, \ldots, d_n$。
接下来 $k$ 行,第 $i$ 行 $n + 1$ 个整数 $a_{i, 1}, a_{i, 2}, \ldots, a_{i, n}, x_i$,每行最后一个整数 $x_i$ 表示 $p_i=x_i\times 10^{-8}$。
输入的 $x_i$ 保证了 $p_i > 0$ 且 $p < 1$。
保证每个 $x_i$ 在所有可能的组合中等概率随机生成。
输出格式:
一行,一个整数,表示答案对 $998244353$ 取模的结果。
如果你不知道如何进行实数取模:可以说明答案一定是有限的,且是有理数,设它的最简分数形式为 $\frac{p}{q}$。如果存在一个整数 $x$ 满足 $x \cdot q \equiv p \pmod{998244353}$ 且 $0 \le x < 998244353$,那么你只需输出 $x$ 的值即可。
由于保证了 $x_i$ 是随机生成的,可以说明以接近 $1$ 的概率答案在模意义下存在。事实上,一个当 $x_i$ 尚不确定时以合理地高的概率给出正确答案的算法足以通过本题,考察复杂的模意义下的有理数的处理不是我们的本意。
数据范围:
对于 $100 \%$ 的数据:
- $1 \le n \le 100$,$1 \le k \le 10000$。
- $d_i \ge 0$,$\sum_i d_i \le 10^7$。
- $0 \le a_{i, j} \le {10}^7$。
- $x_i \ge 1$,$\sum_i x_i < {10}^8$。此即保证了 $p_i > 0$ 和 $p < 1$。
- 保证存在一个 $i \in [1, k]$ 使得对于每个 $j \in [1, n]$ 均有 $a_{i,j} \le d_j$。
- 保证每个 $(a_{i, 1}, a_{i, 2}, \ldots, a_{i, n})$ 作为空间中的点互不相同。
- 保证每个 $x_i$ 在所有可能的组合中等概率随机生成。
由于保证了 $x_i$ 是随机生成的,可以说明以接近 $1$ 的概率答案在模意义下存在。事实上,一个当 $x_i$ 尚不确定时以合理地高的概率给出正确答案的算法足以通过本题,考察复杂的模意义下的有理数的处理不是我们的本意。
样例中的 $x_i$ 不是随机生成的,仅为理解题意所用。
考虑设 $f_i$ 表示从第 $i$ 个点走到终点的期望步数。
显然 $f_i$ 由两部分构成:一是直接走到终点的期望,另一是散入天际后再走到终点的期望。
先考虑如何计算第一部分。记 $q_i$ 表示从第 $i$ 个点直接走到终点的概率,并记 $P=\sum_{i=1}^{k} p_i$ ,则
若存在 $j$ 使得 $a_{i,j} > d_j$ ,则第 $i$ 个点永远无法直接走到终点,即 $q_i = 0$ 。
否则第 $i$ 个点走到终点需要走 $s_i = \sum_{j = 1}^{n}(d_j - a_{i,j})$ 。
- 每步不散入天际的概率是 $1-P$ ,总概率为 $(1-P)^{s_i}$ 。
- 走 $s_i$ 步有 $n^{s_i}$ 种走法,其中只有 $\frac{s_{i} !}{\prod_{j=1}^n\left(d_j-a_{i, j}\right) !}$ 种走法能到达终点
因此有
那么这部分的答案就是 $q_i\cdot s_i$ 。
接着考虑较为复杂的第二部分。如果我们直接用 $f_j$ 来表示 $f_i$ ,则 $f$ 就成了一个 $k$ 元线性方程组
如果使用高斯消元,复杂度就到了 $\mathcal{O}(k^3)$ ,因此我们考虑其他方法。
注意到无论从哪里散入天际,接着走到终点的期望都是一定的,不妨设为 $r$ ,显然
则我们只需考虑从第 $i$ 个点走,期望散入天际的步数 $g_i$ ,并和 $r$ 加起来就是第二部分了。
不考虑走到终点停下,期望散入天际的步数有
而刚才未考虑的这一部分的期望显然为「走到终点的期望」加上「走到终点后的期望」,有
则
由此,我们得知 $f_i$ 有
根据 $r = \sum_{i=1}^{k}\frac{p_i\cdot f_i}{P}$ ,将 $f_i$ 代入,得
整理一下
最后把 $r$ 代回,得到
时间复杂度 $\mathcal{O}(kn\log V + V)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
const int mod = 998244353;
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(115))
#define K ((int)(1e4 + 15))
#define M ((int)(1e7 + 15))
const int i1e8 = 205817851;
const int V = 1e7;
int qpow(int a,int b)
{
int ans = 1;
for(; b; b >>= 1) {
if(b & 1) { ans = ans * a % mod; }
a = a * a % mod;
}
return ans;
}
int n,k,q0,r,sump,d[N],a[K][N],p[K],flg[K],fac[M];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
fac[0] = 1;
for(int i = 1; i <= V; i++) fac[i] = fac[i - 1] * i % mod;
cin >> n >> k;
for(int i = 1; i <= n; i++) cin >> d[i];
for(int i = 1; i <= k; i++)
{
flg[i] = 1;
for(int j = 1; j <= n; j++)
{
cin >> a[i][j];
flg[i] &= (d[j] >= a[i][j]);
}
cin >> p[i];
p[i] = p[i] * i1e8 % mod; sump = (sump + p[i]) % mod;
}
for(int i = 1; i <= k; i++)
{
if(flg[i])
{
int q = 1, s = 0;
for(int j = 1; j <= n; j++)
{
s += d[j] - a[i][j];
q = q * qpow(fac[d[j] - a[i][j]], mod - 2) % mod;
}
q = q * qpow(((1 - sump) % mod + mod) % mod, s) % mod * fac[s] % mod * qpow(qpow(n, s), mod - 2) % mod;
r = (r + p[i] * (((1 - q) % mod + mod) % mod) % mod) % mod;
}else { r = (r + p[i]) % mod; }
}
r = (r == 0) ? 0 : qpow(((sump * sump % mod * qpow(r, mod - 2) % mod - sump) % mod + mod) % mod, mod - 2);
q0 = 1; int s = 0;
for(int i = 1; i <= n; i++) {
s += d[i], q0 = q0 * qpow(fac[d[i]], mod - 2) % mod;
}
q0 = q0 * qpow(((1 - sump) % mod + mod) % mod, s) % mod * fac[s] % mod * qpow(qpow(n, s), mod - 2) % mod;
cout << ((1 - q0) % mod + mod) % mod * (r + qpow(sump, mod - 2)) % mod << '\n';
return 0;
}
参考文献: