题目
对于一个n*m的有值矩阵,只能往下和往右走,求(1,1)到(n,m)路径经过值集合的Mex
思路
2023广东ICPC省赛 I-路径规划(set) - 知乎 (zhihu.com)学习了Resot佬的题解,听说他在准备升学考试,祝他取得好成绩!
我们可以枚举从0,1,...,n * m - 1这些值所在的位置(x,y),在当前位置有机会经过的两个矩形区域,分别是左上角为(1,1)右下角为(x,y)的矩形和左上角为(x,y)右下角为(n,m)的矩形。
那么我们取下一个点的时候,用multiset的二分找到下一个点所在的区域,并把所在区域删掉,然后再往multiset中加入两个可达的矩阵区域。当遍历到的值所在位置不在所有有效区域中时,输出当前这个值。
这种每找到一个区间区间删掉,再加入两个有效区间的方法,可以保证路径经过的值的无序性。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
typedef pair<int, int> PII;
const int mod = 1e9 + 7, N = 1e5 + 10;
struct node
{
int x, y, dx, dy;
node() {}
node(int a, int b, int c, int d): x(a), y(b), dx(c), dy(d) {}
bool operator < (const node &W) const
{
if (x == W.x) return y < W.y;
return x < W.x;
}
};
void solve()
{
int n, m; cin >> n >> m;
vector<PII>a(n * m);
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
int x; cin >> x;
a[x] = {i, j};
}
multiset<node>s;
s.insert(node(1, 1, n, m));
int mex = 0;
for(int k = 0; k < n * m; k ++)
{
auto [x, y] = a[k];
auto p = prev(s.upper_bound(node(x, y, n, m)));
auto it = *p;
if(x >= it.x && x <= it.dx && y >= it.y && y <= it.dy)
{
mex ++;
s.erase(p);
s.insert({it.x, it.y, x, y});
s.insert({x, y, it.dx, it.dy});
}
else break;
}
cout << mex << '\n';
}
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int t = 1; cin >> t;
while(t --)
{
solve();
}
}