CF1042E Vasya and Magic Matrix 题解
题意:
瓦西亚得到了一个大小为 $n \times m$ 的魔法矩阵 $a$。矩阵的行从上到下编号为 $1$ 到 $n$,列从左到右编号为 $1$ 到 $m$。设 $a_{ij}$ 是第 $i$ 行和第 $j$ 列的交点处的元素。
瓦西亚还得到了一个芯片。最初,芯片位于第 $r$ 行和第 $c$ 列的交点处(即元素 $a_{rc}$ 处)。瓦西亚执行以下过程,只要可能:在所有矩阵元素中,其值小于芯片所在元素的值,瓦西亚随机且等概率地选择一个元素,并将芯片移动到该元素。
移动芯片后,他将其得分增加到这些元素之间的欧几里德距离的平方(即芯片现在所在的元素与芯片移动前所在的元素之间的距离)。当没有元素的值小于芯片所在元素的值时,过程结束。
矩阵元素之间的欧几里德距离,其坐标分别为 $(i_1, j_1)$ 和 $(i_2, j_2)$,等于 $\sqrt{(i_1-i_2)^2 + (j_1-j_2)^2}$。
计算瓦西亚最终得分的期望值。
可以证明答案可以表示为 $\frac{P}{Q}$,其中 $P$ 和 $Q$ 是互质的整数,并且 $Q \not\equiv 0\pmod{998244353}$。以 $P \cdot Q^{-1} \pmod{998244353}$ 的形式输出值。
输入格式:
输入的第一行包含两个整数 $n$ 和 $m$ $(1 \le n, m \le 1,000)$ —— 矩阵 $a$ 的行数和列数。
接下来的 $n$ 行包含矩阵 $a$ 的描述。第 $i$ 行包含 $m$ 个整数 $a_{i1}, a_{i2}, \dots, a_{im}$ $(0 \le a_{ij} \le 10^9)$。
接下来的一行包含两个整数 $r$ 和 $c$ $(1 \le r \le n, 1 \le c \le m)$ —— 芯片当前所在的行号和列号。
输出格式:
以问题陈述中描述的格式输出瓦西亚最终得分的期望值。
因为一个点 $i$ 只会被权值比 $a_i$ 小的 $j$ 贡献,所以我们可以先把所有的点按权值顺序排序。
设 $f_i$ 表示第 $i$ 个点作为起点的期望,记有 $T$ 个点的权值小于 $a_i$ 则
因为已经排序过了,所以这个式子可以很好的前缀和优化,不过需要先把距离拆开来
于是我们只要维护 $\sum x_j,~\sum y_j,~\sum(x_j^2+y_j^2),~\sum f_j$ 这四个量就可以 $\mathcal{O}(\log V)$ 转移了
时间复杂度 $\mathcal{O}(nm \log 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; }
void add(int &x,int y) { (x += y) >= mod ? x -= mod : 0; }
#define N ((int)(1e6 + 15))
#define sq(x) ((x) * (x))
int tot, sumx, sumy, sump, sumdp, dp[N];
struct node { int x, y, v; } p[N];
int qpow(int a, int b)
{
int r = 1;
while(b)
{
if(b & 1) r = r * a % mod;
b >>= 1; a = a * a % mod;
}
return r;
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
int n, m; cin >> n >> m;
for(int i = 1; i <= n; i++)
for(int j = 1, x; j <= m; j++) { cin >> x, p[++tot] = {i, j, x}; }
int sx, sy; cin >> sx >> sy;
sort(p + 1, p + 1 + tot, [](node a, node b) { return a.v < b.v; });
for(int i = 1, l = 1; i <= tot; i++)
{
dp[i] = 0;
if(p[i].v != p[l].v) {
while(l < i) {
add(sumx, p[l].x), add(sumy, p[l].y);
add(sump, sq(p[l].x) + sq(p[l].y)); add(sumdp, dp[l]); ++l;
}
}
add(dp[i], (l - 1) * (sq(p[i].x) + sq(p[i].y)) % mod);
add(dp[i], mod - 2 * (p[i].x * sumx % mod + p[i].y * sumy % mod) % mod);
add(dp[i], (sump + sumdp) % mod);
dp[i] = dp[i] * qpow(l - 1, mod - 2) % mod;
if(p[i].x == sx && p[i].y == sy) return cout << dp[i] << '\n', 0;
}
return 0;
}
参考文献:
[1] https://www.luogu.com.cn/article/ecl7uhhf
题外话:
ChatGPT 的翻译水平确实还可以,比机翻强多了。