zoukankan      html  css  js  c++  java
  • CF1606D Red-Blue Matrix

    传送门


    题意:给一个(n*m)的矩阵,让你把一些行涂成红色,剩下的涂成蓝色,但不能都涂红或蓝。问在这个基础上,能否从某一列将矩阵分成两半,使左半矩阵的红色部分的每一个数都大于蓝色部分的每一个数,而右半矩阵的蓝色部分的每一个数都大于红色部分的每一个数。((2 leqslant n,m leqslant 5 imes 10^5,n cdot m leqslant 10^6)


    这题看起来贼吓人,比赛的时候做出来的人竟然还没E题多。我承认我也被吓着了,想了一个很复杂,而且也不好实现的图论相关的算法。

    实际上这题很暴力的。最为关键的一点在于,先把每一行按首元素从小到大排序。这样一定是前几行涂成蓝色,后几行涂成红色(否则第一个元素就不满足要求)。然后我们枚举分割矩阵的那一列(k),再枚举涂成蓝色的行数(x),那么只要判断左半矩阵前(x)行的最大值是否小于后(n - x)行的最小值,以及右半矩阵前(x)行的最小值是否大于后(n-x)行的最大值。而这些,可以在(O(nm))下预处理出从四个角向中间延伸的二维前(后)缀最大(小)值。

    因此时间复杂度是(O(nlog 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;
    }
    
  • 相关阅读:
    最大连续子数组问题之一维数组
    敏捷开发读后感
    第一次作业总结
    OS X(10.10) python3.4 matplotlib的安装
    XCODE 6.1.1 配置GLFW
    python装饰器(decorator)
    Android实现Service永久驻留
    软件项目管理第2次作业:豆瓣测评
    软件项目管理第1次作业:四则运算生成器
    软件项目管理第0次作业:如果一定要改变世界的话,为什么不用最酷的方式呢
  • 原文地址:https://www.cnblogs.com/mrclr/p/15503120.html
Copyright © 2011-2022 走看看