1. 程式人生 > 其它 >CF1606D Red-Blue Matrix

CF1606D Red-Blue Matrix

傳送門


題意:給一個\(n*m\)的矩陣,讓你把一些行塗成紅色,剩下的塗成藍色,但不能都塗紅或藍。問在這個基礎上,能否從某一列將矩陣分成兩半,使左半矩陣的紅色部分的每一個數都大於藍色部分的每一個數,而右半矩陣的藍色部分的每一個數都大於紅色部分的每一個數。(\(2 \leqslant n,m \leqslant 5 \times 10^5,n \cdot m \leqslant 10^6\)


這題看起來賊嚇人,比賽的時候做出來的人竟然還沒E題多。我承認我也被嚇著了,想了一個很複雜,而且也不好實現的圖論相關的演算法。

實際上這題很暴力的。最為關鍵的一點在於,先把每一行按首元素從小到大排序。這樣一定是前幾行塗成藍色,後幾行塗成紅色(否則第一個元素就不滿足要求)。然後我們列舉分割矩陣的那一列\(k\)

,再列舉塗成藍色的行數\(x\),那麼只要判斷左半矩陣前\(x\)行的最大值是否小於後\(n - x\)行的最小值,以及右半矩陣前\(x\)行的最小值是否大於後\(n-x\)行的最大值。而這些,可以在\(O(nm)\)下預處理出從四個角向中間延伸的二維前(後)綴最大(小)值。

因此時間複雜度是\(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;
}