CF1042E Vasya and Magic Matrix
题意
一个n
行m
列的矩阵,每个位置有权值
给定一个出发点,每次可以等概率的移动到一个权值小于当前点权值的点,同时得分加上两个点之间欧几里得距离的平方(欧几里得距离:,问得分的期望
思路
按照计算期望的一般思路
我们可以考虑先计算小的点的期望,在用小的点的期望计算大的点的期望
我们先从小到大排序
转移方程
前缀和优化
-
所以我们只要知道
和
就可以O(1)
转移 -
我们维护前缀和,,,,
-
ans = (sum + x2 + y2) % mod;
LL inv = quickpow(p - 1, mod - 2);
dp[j] = ((ans - sx * 2 * node[j].x - sy * 2 * node[j].y) % mod + mod) % mod;
dp[j] = (dp[j] + LL(p - 1) * node[j].x * node[j].x % mod + LL(p - 1) * node[j].y * node[j].y % mod) % mod;
dp[j] = dp[j] * inv % mod;
代码
#include <bits/stdc++.h>
using namespace std;
struct Node {
int data;
int x;
int y;
friend bool operator<(const Node& a, const Node& b)
{
return a.data < b.data;
}
};
const int maxn = 1001 * 1001 * 5;
Node node[maxn];
typedef long long LL;
const LL mod = 998244353;
LL quickpow(LL m, LL p)
{
LL res = 1;
while (p) {
if (p & 1)
res = res * m % mod;
m = m * m % mod;
p >>= 1;
}
return res;
}
LL dp[maxn];
int main()
{
int n, m, k = 0;
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
scanf("%d", &node[++k].data);
node[k].x = i;
node[k].y = j;
}
}
int ex, ey;
scanf("%d%d", &ex, &ey);
sort(node + 1, node + 1 + k);
bool flag = false;
LL sx, x2, sy, y2, sum, ans;
sum = sx = sy = x2 = y2 = 0;
for (int i = 1; i <= k;) {
int p = i;
while (++i <= k && node[i].data == node[p].data)
;
ans = (sum + x2 + y2) % mod;
LL inv = quickpow(p - 1, mod - 2);
for (int j = p; j < i; j++) {
dp[j] = ((ans - sx * 2 * node[j].x - sy * 2 * node[j].y) % mod + mod) % mod;
dp[j] = (dp[j] + LL(p - 1) * node[j].x * node[j].x % mod + LL(p - 1) * node[j].y * node[j].y % mod) % mod;
dp[j] = dp[j] * inv % mod;
if (node[j].x == ex && node[j].y == ey) {
flag = true;
ans = dp[j];
break;
}
}
if (flag)
break;
for (int j = p; j < i; j++)
sum = (sum + dp[j]) % mod,
sx += node[j].x,
x2 += LL(node[j].x) * node[j].x,
sy += node[j].y,
y2 += LL(node[j].y) * node[j].y;
}
printf("%lld\n", ans);
return 0;
}