Codeforces Round #510 (Div. 2) E---谈处理数差平方和问题的套路技巧

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38786088/article/details/82777532

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] 几乎可由所有dp[j] (j<i)转移而来,这会使时间复杂度为O(n*n)

d p [ i ] = 1 k 1 1 j &lt; k ( d p [ j ] + ( x i x j ) 2 + ( y i y j ) 2 ) dp[i] = \frac {1}{k-1} \sum_{1\leq j &lt;k}(dp[j]+(x_i-x_j)^2+(y_i-y_j)^2)
d p [ i ] = 1 k 1 1 j &lt; k d p [ j ] + 1 k 1 1 j &lt; k ( ( x i x j ) 2 + ( y i y j ) 2 ) dp[i] = \frac {1}{k-1}\sum_{1\leq j &lt;k}dp[j]+\frac {1}{k-1}\sum_{1\leq j &lt;k}((x_i-x_j)^2+(y_i-y_j)^2)
这样还是不够,我们可以在记录前k-1项dp[j]的和;这也是我们转化为一维的目的,但是后部还是需要(xi,yi)与前面k-1个点逐一2求两点距离平方!

套路:去平方,化为和值来处理!这是处理平方和问题的基本做法!
d p [ i ] = 1 k 1 ( 1 j &lt; k d p [ j ] + 1 j &lt; k x j 2 + 1 j &lt; k y j 2 2 x i 1 j &lt; k x j 2 y i 1 j &lt; k y j ) + x i 2 + y i 2 dp[i] = \frac {1}{k-1}(\sum_{1\leq j &lt;k}dp[j]+\sum_{1\leq j &lt;k}x_j^2+\sum_{1\leq j &lt;k}y_j^2-2x_i\sum_{1\leq j &lt;k}x_j-2y_i\sum_{1\leq j &lt;k}y_j)+x_i^2+y_i^2

我们第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;
}


猜你喜欢

转载自blog.csdn.net/qq_38786088/article/details/82777532