CF1042E Vasya and Magic Matrix 期望 dp
CF1042E Vasya and Magic Matrix 期望 dp
考虑到一个点只能由权值小于它的点转移过来,我们考虑把所有点按照权值排序组成一个序列。
我们设 \(f_i\) 表示序列上从第 \(i\) 点出发的期望得分是多少。那么我们显然有:
\[f_{i}=\sum\limits_{a_j<a_i}\frac{(x_j-x_i)^2+(y_j-y_i)^2+f_j}{num}
\]
其中,\(num\) 计数的是所有权值小于 \(a_i\) 的数。
我们按照权值分组,把权值相同的分成一组,这样,在每一组中的数只能由前面的数转移过来。
我们把分子拆开,可以得到:
\[x_j^2-2x_ix_j+x_i^2+y_j^2-2y_jy_i+y_i^2+f_j
\]
显然可以用前缀和维护,可以 \(O(1)\) 进行转移。
对于分母的逆元,我们预处理线性求逆元即可。
不过这个题实现宽泛,及时现求也可以过。
代码:
#include<bits/stdc++.h>
#define dd double
#define ld long double
#define ll long long
#define uint unsigned int
#define ull unsigned long long
#define N 1000100
#define M number
using namespace std;
const int INF=0x3f3f3f3f;
const ll mod=998244353;
template<typename T> inline void read(T &x) {
x=0; int f=1;
char c=getchar();
for(;!isdigit(c);c=getchar()) if(c == '-') f=-f;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
x*=f;
}
struct node{
int x,y,val;
inline bool operator < (const node &b) const{
return val<b.val;
}
};
node a[N];
int n,m,r,c;
ll num,numx,numy,numx2,numy2;
ll nownum,nownumx,nownumy,nownumx2,nownumy2;
ll sumf,nowsumf;
ll f[N],g[N],ansid,inv[N];
inline ll ksm(ll a,ll b,ll mod){
ll res=1;
while(b){
if(b&1) (res*=a)%=mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int main(){
read(n);read(m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++){
int now=(i-1)*m+j;
read(a[now].val);a[now].x=i;a[now].y=j;
}
read(r);read(c);
sort(a+1,a+n*m+1);
inv[1]=1;for(int i=2;i<=n*m;i++) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
for(int i=1;i<=n*m;i++){
if(a[i].val!=a[i-1].val){
num+=nownum;numx+=nownumx;numy+=nownumy;
numx2+=nownumx2;numy2+=nownumy2;
nownum=nownumx=nownumy=nownumx2=nownumy2=0;
sumf+=nowsumf;nowsumf=0;
}
f[i]=(num*(a[i].x*a[i].x+a[i].y*a[i].y)%mod+numx2+numy2-2*a[i].x*numx%mod-2*a[i].y*numy%mod+sumf)%mod*inv[num]%mod;
nownum++;nownumx+=a[i].x;nownumy+=a[i].y;nownumx2+=a[i].x*a[i].x;nownumy2+=a[i].y*a[i].y;nowsumf+=f[i];
nownumx%=mod;nownumy%=mod;nownumx2%=mod;nownumy2%=mod;nowsumf%=mod;
if(a[i].x==r&&a[i].y==c){ansid=i;break;}
}
printf("%lld\n",f[ansid]);
return 0;
}