CF1606D Red-Blue Matrix
阿新 • • 發佈:2021-11-03
傳送門
題意:給一個\(n*m\)的矩陣,讓你把一些行塗成紅色,剩下的塗成藍色,但不能都塗紅或藍。問在這個基礎上,能否從某一列將矩陣分成兩半,使左半矩陣的紅色部分的每一個數都大於藍色部分的每一個數,而右半矩陣的藍色部分的每一個數都大於紅色部分的每一個數。(\(2 \leqslant n,m \leqslant 5 \times 10^5,n \cdot m \leqslant 10^6\))
這題看起來賊嚇人,比賽的時候做出來的人竟然還沒E題多。我承認我也被嚇著了,想了一個很複雜,而且也不好實現的圖論相關的演算法。
實際上這題很暴力的。最為關鍵的一點在於,先把每一行按首元素從小到大排序。這樣一定是前幾行塗成藍色,後幾行塗成紅色(否則第一個元素就不滿足要求)。然後我們列舉分割矩陣的那一列\(k\)
因此時間複雜度是\(O(n\log n+nm)\)的。
Debug的時候才知道,vector的resize(n, x)
是把新開闢出來的空間的初始賦值成x,但是已經開闢出來的元素值不變。
#include<bits/stdc++.h> using namespace std; #define enter puts("") #define space putchar(' ') #define Mem(a, x) memset(a, x, sizeof(a)) #define In inline #define forE(i, x, y) for(int i = head[x], y; ~i && (y = e[i].to); i = e[i].nxt) typedef long long ll; typedef double db; const int INF = 0x3f3f3f3f; const db eps = 1e-8; const int maxn = 5e5 + 5; In ll read() { ll ans = 0; char ch = getchar(), las = ' '; while(!isdigit(ch)) las = ch, ch = getchar(); while(isdigit(ch)) ans = (ans << 1) + (ans << 3) + ch - '0', ch = getchar(); if(las == '-') ans = -ans; return ans; } In void write(ll x) { if(x < 0) x = -x, putchar('-'); if(x >= 10) write(x / 10); putchar(x % 10 + '0'); } int n, m, id[maxn]; vector<vector<int> > a; vector<vector<int> > lMax, lMin, rMin, rMax; In void print(int x, int y) { puts("YES"); vector<char> ans(n + 1, 'R'); for(int i = 1; i <= x; ++i) ans[id[i]] = 'B'; for(int i = 1; i <= n; ++i) putchar(ans[i]); space, write(y), enter; } In void solve() { for(int j = 1; j < m; ++j) { for(int i = 1; i < n; ++i) if(lMax[i][j] < lMin[i + 1][j] && rMin[i][j + 1] > rMax[i + 1][j + 1]) return (void)print(i, j); } puts("NO"); } int main() { int T = read(); while(T--) { n = read(), m = read(); a.resize(n + 1); for(int i = 1; i <= n; ++i) a[i].resize(m + 1), id[i] = i; for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) a[i][j] = read(); sort(id + 1, id + n + 1, [&](int x, int y) {return a[x][1] < a[y][1];}); lMax.clear(), lMax.resize(n + 1), lMax[0].resize(m + 1, -INF); for(int i = 1; i <= n; ++i) { lMax[i].resize(m + 1, -INF); for(int j = 1; j <= m; ++j) lMax[i][j] = max(a[id[i]][j], max(lMax[i - 1][j], lMax[i][j - 1])); } lMin.clear(), lMin.resize(n + 2), lMin[n + 1].resize(m + 1, INF); for(int i = n; i; --i) { lMin[i].resize(m + 1, INF); for(int j = 1; j <= m; ++j) lMin[i][j] = min(a[id[i]][j], min(lMin[i + 1][j], lMin[i][j - 1])); } rMin.clear(), rMin.resize(n + 1), rMin[0].resize(m + 2, INF); for(int i = 1; i <= n; ++i) { rMin[i].resize(m + 2, INF); for(int j = m; j; --j) rMin[i][j] = min(a[id[i]][j], min(rMin[i - 1][j], rMin[i][j + 1])); } rMax.clear(), rMax.resize(n + 2), rMax[n + 1].resize(m + 2, -INF); for(int i = n; i; --i) { rMax[i].resize(m + 2, -INF); for(int j = m; j; --j) rMax[i][j] = max(a[id[i]][j], max(rMax[i + 1][j], rMax[i][j + 1])); } solve(); } return 0; }