CF 510(Div.2) E、Vasya and Magic Matrix
题意: n*m的矩阵中,每个格子有一个整数a[i][j],人能从格子(xi,yi) 走到格子(xj,yj),
当且仅当a[xi][yi] >a[xj][yj]) ,其花费为距离的平方,如果有多个能走的点,等概率选择
其中某个点,仅当没有格子能走了,才停止。
问人在格子(r , c),将要花费额的期望(P/Q)%(998244353)。
一、二维化为一维线性数组
用结构体node保存每个格子的x、y、val(行、列、值),按权值小到大排序,所以可以从右边走到不等于本身val的所有格子,连续且从首开始。
例:蓝色格子可以走到红色格子任何一格,等概率
二、概率DP
定义:dp[i]为人在蓝色格子i上,走到停止,花费额的期望值。
它等可能走到所有红格子。走到红格子j,花费为dp[j] + (xi-xj)(xi-xj)+(yi-yj)(yi-yj),所有花费和除以k(k为红格子数)即为dp[i]
d
p
[
i
]
=
∑
1
≤
j
<
k
<
i
,
n
o
d
e
[
k
−
1
]
.
v
a
l
<
n
o
d
e
[
i
]
.
v
a
l
且
n
o
d
e
[
k
]
.
v
a
l
=
n
o
d
e
[
i
]
.
v
a
l
(
d
p
[
j
]
+
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
)
/
(
k
−
1
)
dp[i] = \sum_{1\leq j <k<i,node[k-1].val<node[i].val且node[k].val=node[i].val}(dp[j]+(x_i-x_j)^2+(y_i-y_j)^2)/(k-1)\\
dp[i]=1≤j<k<i,node[k−1].val<node[i].val且node[k].val=node[i].val∑(dp[j]+(xi−xj)2+(yi−yj)2)/(k−1)
三、优化状态转移方程
dp[i] 几乎可由所有dp[j] (j<i)转移而来,这会使时间复杂度为O(n*n)
d
p
[
i
]
=
1
k
−
1
∑
1
≤
j
<
k
(
d
p
[
j
]
+
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
)
dp[i] = \frac {1}{k-1} \sum_{1\leq j <k}(dp[j]+(x_i-x_j)^2+(y_i-y_j)^2)
dp[i]=k−111≤j<k∑(dp[j]+(xi−xj)2+(yi−yj)2)
d
p
[
i
]
=
1
k
−
1
∑
1
≤
j
<
k
d
p
[
j
]
+
1
k
−
1
∑
1
≤
j
<
k
(
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
)
dp[i] = \frac {1}{k-1}\sum_{1\leq j <k}dp[j]+\frac {1}{k-1}\sum_{1\leq j <k}((x_i-x_j)^2+(y_i-y_j)^2)
dp[i]=k−111≤j<k∑dp[j]+k−111≤j<k∑((xi−xj)2+(yi−yj)2)
这样还是不够,我们可以在记录前k-1项dp[j]的和;这也是我们转化为一维的目的,但是后部还是需要(xi,yi)与前面k-1个点逐一2求两点距离平方!
套路:去平方,化为和值来处理!这是处理平方和问题的基本做法!
d
p
[
i
]
=
1
k
−
1
(
∑
1
≤
j
<
k
d
p
[
j
]
+
∑
1
≤
j
<
k
x
j
2
+
∑
1
≤
j
<
k
y
j
2
−
2
x
i
∑
1
≤
j
<
k
x
j
−
2
y
i
∑
1
≤
j
<
k
y
j
)
+
x
i
2
+
y
i
2
dp[i] = \frac {1}{k-1}(\sum_{1\leq j <k}dp[j]+\sum_{1\leq j <k}x_j^2+\sum_{1\leq j <k}y_j^2-2x_i\sum_{1\leq j <k}x_j-2y_i\sum_{1\leq j <k}y_j)+x_i^2+y_i^2
dp[i]=k−11(1≤j<k∑dp[j]+1≤j<k∑xj2+1≤j<k∑yj2−2xi1≤j<k∑xj−2yi1≤j<k∑yj)+xi2+yi2
我们第1个节点从左到右遍历,必须维护dp[i]、x2、y2、x、y的前缀和!
除以k-1,变成乘以k-1的逆元!现在就是个简单的线性dp,去实现吧!
#include <bits/stdc++.h>
#define llt long long
using namespace std;
const llt mod = 998244353;
const int N = 1e6+777;
struct node{
int x,y;
int val;
bool operator <(node &a){
return val<a.val;
}
}p[N];
llt quick_mod(llt x,llt aa){
llt res = 1;
for(;aa;aa>>=1,x=x*x%mod)
if(aa&1) res = res*x%mod;
return res;
}
llt a[10][10]={0};
llt dp[N];
int main( ){
int n,m;
scanf("%d%d",&n,&m);
int cnt = 0;
for(int i=1;i<=n;++i)
for(int j=1;j<=m;++j){
scanf("%d",&p[cnt].val);
p[cnt].x = i;
p[cnt++].y = j;
}
int r,c;
scanf("%d %d",&r,&c);
sort(p,p+cnt);
p[cnt].val = -1;
// a[0][2] x^2 的 和
// a[0][1] x 的 和
// a[1][2] y^2 的 和
// a[1][1] y 的 和
// k val小于它的个数 sum为val小于它的dp和 sum1为val相等的dp值
llt k=0,sum = 0,sum1=0;
for(int i=0;i<=cnt;++i){
if(i&&p[i].val!=p[i-1].val) {
for(int x=0;x<2;++x)
for(int y=1;y<=2;++y)
(a[x][y] += a[x+2][y])%=mod,a[x+2][y] = 0;
k = i;
(sum+=sum1)%=mod;
sum1 = 0;
}
dp[i] = (sum+a[0][2]+a[1][2]-2ll*a[0][1]*p[i].x-2ll*a[1][1]*p[i].y)%mod*quick_mod(k,mod-2);
dp[i] %= mod;
if(dp[i]<0) dp[i] += mod;
if(k) (dp[i] += (p[i].x*p[i].x+p[i].y*p[i].y))%=mod;
if(p[i].x==r&&p[i].y==c) {
cout<<dp[i]<<endl;
break;
}
( sum1 += dp[i])%=mod;
(a[2][2] += p[i].x*p[i].x)%=mod;
(a[3][2] += p[i].y*p[i].y)%=mod;
(a[2][1] += p[i].x)%=mod;
(a[3][1] += p[i].y)%=mod;
}
return 0;
}