o(1)记录一个矩阵
o(1)记录一个矩阵
代码:
bool check(int x){ memset(dot, 0, sizeof(dot)); int cnt = 0; //处理记矩阵扩展一行一列后的四个角的坐标 //预处理 为使每个矩阵中的每个点权值在原先基础上+1 for(int i = 1; i <= x; i++){ dot[a[i].x1][a[i].y1] ++; dot[a[i].x2 + 1][a[i].y2 + 1] ++; dot[a[i].x1][a[i].y2 + 1] --; dot[a[i].x2 + 1][a[i].y1] --; } // 遍历 dot[i][j]就代表 被几个矩阵覆盖过 for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ dot[i][j] += dot[i][j - 1] + dot[i - 1][j] - dot[i - 1][j - 1]; if(dot[i][j]) cnt++; } } return cnt == n * m; }
例题
周周选妃
链接:https://ac.nowcoder.com/acm/contest/29320/K
来源:牛客网
今天是瓜瓜大王选妃的日子,所有 MM 排成了 n×mn \times mn×m 的方阵。
每次瓜瓜可以任意选择一个矩形区域,但是瓜瓜又希望能够雨露均沾,每个 MM 都能被选到。
瓜瓜会做 kkk 次选择,你需要告诉他一个最早的一个选择 tit_iti,自此 tit_iti 以后(包括 tit_iti)所有人都被选到过了。如果不存在,输出 −1-1−1。
思路:
二分 每次o(1)标记选择矩阵#include<bits/stdc++.h>#define FF ios::sync_with_stdio(false); cin.tie(0), cout.tie(0);
using namespace std; const int N = 1e5 + 10; int n,m,k; int cnt; int dot[1000][1000], c[1000]; struct node { int x1, x2, y1, y2; }a[N]; bool check(int x){ memset(dot, 0, sizeof(dot)); int cnt = 0; //预处理 为使后面遍历 时每个矩阵内的点的权值都加1(这当于o(1)记录了一个矩阵 这样就不会超时了)
//如果有重叠那就是重叠数了 for(int i = 1; i <= x; i++){ dot[a[i].x1][a[i].y1] ++; dot[a[i].x2 + 1][a[i].y2 + 1] ++; dot[a[i].x1][a[i].y2 + 1] --; dot[a[i].x2 + 1][a[i].y1] --; } // 遍历 dot[i][j] 就是 该点被几个矩阵覆盖过 for(int i = 1; i <= n; i++){ for(int j = 1; j <= m; j++){ dot[i][j] += dot[i][j - 1] + dot[i - 1][j] - dot[i - 1][j - 1]; if(dot[i][j]) cnt++; } } //如果所有点都被覆盖过 返回真 return cnt == n * m; } void solve() { cin >> n >> m >> k; int flag = 0; for(int i = 1; i <= k; i++){ cin >> a[i].x1 >> a[i].y1 >> a[i].x2 >> a[i].y2; } int l = 1; int r = k + 1;//二分答案 while(l < r){ int mid = (l + r) / 2; if(check(mid)) r = mid; else l = mid + 1; } if (r > k) cout << -1 << "\n"; else cout << r << "\n"; } int main(){ FF; int t = 1; while(t--){ solve(); } return 0; }

浙公网安备 33010602011771号