ABC 224 | E - Integers on Grid

题目描述

给定一个\(H \times W\)的矩阵,给定\(N\)个三元组\((r_i, w_i, a_i)\),表示\((r_i, w_i)\)位置的值为\(a_i\),其余格子上数值为\(0\)
\(Takahashi\)将分别以\((r_i, w_i)\)作为起始位置,从当前位置走到同行或者同列且数值大于当前位置的格子处,输出从\((r_i, w_i)\)出发最多能走几步?

数据范围

  • \(2 \le H, W \le 2 \times 10^5\)
  • \(1 \le N \le \min(2 \times 10^5, HW)\)
  • \(1 \le r_i \le H, 1 \le c_i \le W\)
  • \(1 \le a_i \le 10^9\)

解题思路

使用动态规划算法解决问题。

  • 状态表示

\(dp[i]:\)\((r_i, c_i)\)出发能够走的最大步数

由于除给出的\((r_i, c_i)\)位置,其余位置都是\(0\),所以只需对给出的\(n\)个位置进行状态表示,因为从\((r_i, c_i)\)只能转移到某个\((r_j, c_j)\)

  • 状态转移

    • 由于只能转移到数值更大的位置,所以为保证可以进行状态转移,需要对\(n\)个位置的数值进行降序遍历,同时为避免数值相等导致错误转移,需要将数值相等的位置全部进行状态转移,然后统一进行数组更新。
    • 由于只能转移到同行或者同列的位置,所以需要找出当前位置所在行\(r_i\)以及所在列\(c_i\)最大的\(dp\)值,将该值记为\(rmax[r_i], cmax[c_i]\),在每轮状态转移后进行数组更新。
  • 语法问题

    • map默认从小到大进行排序,该题需要进行倒序遍历
    for(auto t = mp.rbegin(); t != mp.rend(); t ++){  //对map进行降序遍历
        for(auto i : t -> second) f[i] = max(rmax[r[i]], cmax[c[i]]);  //t是迭代器,只能使用'->'
        for(auto i : t -> second) {
            rmax[r[i]] = max(f[i] + 1, rmax[r[i]]);
            cmax[c[i]] = max(f[i] + 1, cmax[c[i]]);
        }
    }
    

代码

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <vector>

using namespace std;

const int N = 2e5 + 10;

int h, w, n;
int r[N], c[N], a[N];
int rmax[N], cmax[N];
int f[N];
map<int, vector<int>> mp;

int main()
{
    scanf("%d%d%d", &h, &w, &n);
    for(int i = 1; i <= n; i ++){
        scanf("%d%d%d", &r[i], &c[i], &a[i]);
        mp[a[i]].push_back(i);
    }

    for(auto t = mp.rbegin(); t != mp.rend(); t ++){ 
        for(auto i : t -> second) f[i] = max(rmax[r[i]], cmax[c[i]]);  
        for(auto i : t -> second) {
            rmax[r[i]] = max(f[i] + 1, rmax[r[i]]);
            cmax[c[i]] = max(f[i] + 1, cmax[c[i]]);
        }
    }

    for(int i = 1; i <= n; i ++) printf("%d\n", f[i]);
    return 0;
}

posted @ 2022-06-20 20:03  小菜珠的成长之路  阅读(145)  评论(0)    收藏  举报