题目大意: 给出一个矩阵,每个格子有一个数字,给出一个起点,每次可以往比自己数字小的格子跳,贡献为两点间欧几里得距离的平方,问期望贡献。
题解
先把所有格子按数字大小排,然后从小往大推,对于第
i
i
i 个格子,他可以到达前面所有比他小的格子,设最接近它且比他小的格子的位置为
k
k
k,那么有:
f
[
i
]
=
1
k
∑
j
=
1
k
f
[
j
]
+
(
x
i
−
x
j
)
2
+
(
y
i
−
y
j
)
2
f[i]=\frac 1 k \sum_{j=1}^k f[j]+(x_i-x_j)^2+(y_i-y_j)^2
f[i]=k1j=1∑kf[j]+(xi−xj)2+(yi−yj)2
这种东西维护不了,按照套路把他拆开就能维护了:
f
[
i
]
=
1
k
∑
j
=
1
k
f
[
j
]
+
x
i
2
+
x
j
2
−
2
x
i
x
j
+
y
i
2
+
y
j
2
−
2
y
i
y
j
=
x
i
2
+
y
i
2
+
(
1
k
∑
j
=
1
k
x
j
2
+
y
j
2
+
f
[
j
]
)
−
(
2
x
i
k
∑
j
=
1
k
x
j
)
−
(
2
y
i
k
∑
j
=
1
k
y
j
)
\begin{aligned} f[i]&=\frac 1 k \sum_{j=1}^k f[j]+x_i^2+x_j^2-2x_ix_j+y_i^2+y_j^2-2y_iy_j\\ &=x_i^2+y_i^2+(\frac 1 k \sum_{j=1}^k x_j^2+y_j^2+f[j])-(\frac {2x_i} k\sum_{j=1}^k x_j)-(\frac {2y_i} k\sum_{j=1}^k y_j) \end{aligned}
f[i]=k1j=1∑kf[j]+xi2+xj2−2xixj+yi2+yj2−2yiyj=xi2+yi2+(k1j=1∑kxj2+yj2+f[j])−(k2xij=1∑kxj)−(k2yij=1∑kyj)
统计一下前缀和就好。
代码如下:
#include <cstdio>
#include <algorithm>
using namespace std;
#define maxn 1000010
#define mod 998244353
int n,m,X,Y,a[1010][1010];
int xj[maxn],yj[maxn],j2[maxn],f[maxn],sum_f[maxn];
struct node{int z,x,y;};
node b[maxn];
bool cmp(node x,node y){return x.z<y.z;}
int ksm(int x,int y)
{
int re=1;
while(y)
{
if(y&1)re=1ll*re*x%mod;
x=1ll*x*x%mod;y>>=1;
}
return re;
}
#define inv(x) ksm(x,mod-2)
int main()
{
scanf("%d %d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]),b[(i-1)*m+j]=(node){a[i][j],i,j};
scanf("%d %d",&X,&Y);
sort(b+1,b+n*m+1,cmp);
int last=0;
for(int i=1;i<=n*m;i++)
{
if(b[i].z>b[i-1].z)last=i-1;
if(last)f[i]=((((1ll*b[i].x*b[i].x%mod+1ll*b[i].y*b[i].y%mod)%mod+1ll*j2[last]*inv(last)%mod)%mod
-2ll*xj[last]*inv(last)%mod*b[i].x%mod+mod)%mod-2ll*yj[last]*inv(last)%mod*b[i].y%mod+mod)%mod;
j2[i]=(j2[i-1]+((1ll*b[i].x*b[i].x%mod+1ll*b[i].y*b[i].y%mod)%mod+f[i])%mod)%mod;
xj[i]=(xj[i-1]+b[i].x)%mod; yj[i]=(yj[i-1]+b[i].y)%mod;
if(b[i].x==X&&b[i].y==Y)return printf("%d",f[i]),0;
}
}