Loading

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;
}
posted @ 2021-07-08 16:27  hyl天梦  阅读(38)  评论(0编辑  收藏  举报