CF1042E Vasya and Magic Matrix

传送门

题目看完立马就有想法的题。首先肯定不能二维做,先把矩阵拍成一维,以权值排序。然后肯定就是O(n)的做法。
根据题意,转移只能是单向的,那么大的权值肯定由小的转移而来,设dp为i位置值的期望
那么有转移:
d p [ i ] = ∑ j = 0 i − 1 d p [ j ] + ( x i − x j ) 2 + ( y i − y j ) 2 i dp[i] = \frac{\sum_{j=0}^{i-1} dp[j] + (x_i-x_j)^2+(y_i - y_j)^2} {i} dp[i]=ij=0i1dp[j]+(xixj)2+(yiyj)2
展开合并同类项易得
d p [ i ] = ∑ j = 0 i − 1 ( d p [ j ] + x j 2 + y j 2 ) + i ∗ ( x i 2 + y i 2 ) − 2 ∗ ∑ j = 0 i − 1 ( x j + y j ) i dp[i] = \frac{\sum_{j=0}^{i-1} (dp[j]+x_j^2+y_j^2) +i*(x_i^2+y_i^2) - 2 *\sum_{j=0}^{i-1} {(x_j+y_j)}}{i} dp[i]=ij=0i1(dp[j]+xj2+yj2)+i(xi2+yi2)2j=0i1(xj+yj)
很明显都可以用前缀和处理。
然后就是细节。。
要注意对于权值相同的点,我们需要对其特殊处理。

#include "bits/stdc++.h"
//#define int long long
using namespace std;
#define int long long
const int mod = 998244353;
const int N = 2e6 + 10;
#define pii pair<int,int>
struct node {
    pii p;
    int v;
};
vector<node> v;
int dp[N];
int sum1[N];
int sum2[N];
int sum3[N];
int sum4[N];

int quick_pow(int x, int b) {
    int base = 1;
    while (b) {
        if (b & 1) {
            base = (base * x) % mod;
        }
        x = (x * x) % mod;
        b >>= 1;
    }
    return base;
}

void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= m; ++j) {
            int s;
            cin >> s;
            v.push_back(node{{i, j}, s});
        }
    }
    sort(v.begin(), v.end(), [&](node a, node b) { return a.v < b.v; });
    pii rt;
    cin >> rt.first >> rt.second;
    int pos = 0;
    for (int i = 0; i < v.size(); ++i) {
        if (rt.first == v[i].p.first && rt.second == v[i].p.second) {
            pos = i;
            break;
        }
    }
    dp[0] = 0;
    int last;
    int last1, last2, last3, last4, lastp;
    for (int i = 0; i < v.size(); ++i) {
        int x = v[i].p.first;
        int y = v[i].p.second;
        if (i == 0) {
            last1 = sum1[i] = x * x + y * y;
            last2 = sum2[i] = x;
            last3 = sum3[i] = y;
            last4 = sum4[i] = dp[i];
            last = v[i].v;
            continue;
        }
        if (v[i].v == last) {
            if (v[i].v == v[0].v) {
                dp[i] = 0;
            } else
                dp[i] = (last4 + last1 - (2 * (last3 * y + last2 * x)) % mod + lastp * (x * x + y * y) % mod + mod) %mod *quick_pow(lastp, mod - 2) % mod;
        } else {
            dp[i] = (sum4[i - 1] + sum1[i - 1] - (2 * (sum3[i - 1] * y + sum2[i - 1] * x)) % mod +i * (x * x + y * y) % mod + mod) % mod *quick_pow(i, mod - 2) % mod;
            last1 = sum1[i - 1];
            last2 = sum2[i - 1];
            last3 = sum3[i - 1];
            last4 = sum4[i - 1];
            lastp = i;
        }
        sum1[i] = (sum1[i - 1] + x * x + y * y) % mod;
        sum2[i] = sum2[i - 1] + x;
        sum3[i] = sum3[i - 1] + y;
        sum4[i] = (sum4[i - 1] + dp[i]) % mod;
        last = v[i].v;
    }
    cout << dp[pos] << endl;
}

signed main() {
//    freopen("in.txt", "r", stdin);
    ios::sync_with_stdio(0);
//    cin.tie(0);cout.tie(0);
    solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值