zoukankan      html  css  js  c++  java
  • Codeforces 713D Animals and Puzzle(二维ST表+二分答案)

    题目链接 Animals and Puzzle

    题意  给出一个1e3 * 1e3的01矩阵,给出t个询问,每个询问形如x1,y1,x2,y2

    你需要回答在以$(x1, y1)$为左上角,$(x1, y2)$为右下角的子矩阵中,最大的全1正方形的边长。

    首先考虑DP预处理。

    $f[i][j]$表示以$f[i][j]$为右下角的最大的全1正方形的边长。

    则$f[i][j] = min(f[i - 1][j], f[i][j - 1], f[i - 1][j - 1]) + 1$

    我们对$f[i][j]$构建一张二维ST表,使我们能在$O(1)$的时间复杂度内求出$f[i][j](x1 <= i <= x2, y1 <= j <= y2)$

    但是这样直接查询$f[i][j]$的最大值$(x1 <= i <= x2, y1 <= j <= y2)$是不行的。

    因为查询到的最大全1子正方形并不一定都在以$(x1, y1)$为左上角,$(x1, y2)$为右下角的子矩阵中。

    所以我们需要另外想办法。

    我们可以判断一个答案x是否存在,先求出合法的$f[i][j] >= x$的范围,

    也就是说如果找到$f[i][j] >= x$了,这个找到的全1子正方形一定都在以$(x1, y1)$为左上角,$(x1, y2)$为右下角的子矩阵中。

    显然x是单调的,所以我们可以二分答案。

    时间复杂度$O(nmlognm + t)$

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define rep(i, a, b)	for (int i(a); i <= (b); ++i)
    #define dec(i, a, b)	for (int i(a); i >= (b); --i)
    
    const int N   = 1e3 + 3;
    const int M   = 10;
    
    int   f[N][N][M][M], lg[N];
    int   n, m, x, q;
    
    void ST(){
    	rep(i, 2, 1e3 + 1) lg[i] = lg[i >> 1] + 1;
    	rep(i, 1, n){
    		for (int k = 1; (1 << k) <= m; ++k){
    			rep(j, 1, m - (1 << k) + 1){
    				f[i][j][0][k] = max(f[i][j][0][k - 1], f[i][j + (1 << (k - 1))][0][k - 1]);
    			}
    		}
    	}
    
    	for (int k1 = 1; (1 << k1) <= n; ++k1){
    		rep(i, 1, n - (1 << k1) + 1){
    			for (int k2 = 0; (1 << k2) <= m; ++k2){
    				rep(j, 1, m - (1 << k2) + 1){
    					f[i][j][k1][k2] = max(f[i][j][k1 - 1][k2], f[i + (1 << (k1 - 1))][j][k1 - 1][k2]);
    				}
    			}
    		}
    	}
    }
    
    int query(int x1, int y1, int x2, int y2){
    	int k1 = lg[x2 - x1 + 1], k2 = lg[y2 - y1 + 1];
    	x2 = x2 - (1 << k1) + 1;
    	y2 = y2 - (1 << k2) + 1;
    	return max(max(f[x1][y1][k1][k2], f[x1][y2][k1][k2]), max(f[x2][y1][k1][k2], f[x2][y2][k1][k2]));
    }
    
    
    int main(){
    
    	freopen("1.txt", "r", stdin);
    	freopen("2.txt", "w", stdout);
    	
    	scanf("%d%d", &n, &m);
    
    	rep(i, 1, n){
    		rep(j, 1, m){
    			int x;
    			scanf("%d", &x);
    			if (x) f[i][j][0][0] = min(f[i - 1][j - 1][0][0],
    						min(f[i - 1][j][0][0], f[i][j - 1][0][0])) + 1;
    			else f[i][j][0][0] = 0;
    		}
    	}
    
    	ST();
    	scanf("%d", &q);
    	while (q--){
    		int x1, y1, x2, y2;
    		scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
    		int l = 0, r = min(x2 - x1, y2 - y1) + 1, ans = 0;
    		while (l <= r){
    			int mid = (l + r) >> 1;
    			if (query(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid) l = mid + 1, ans = mid;
    			else r = mid - 1;
    		}
    
    		printf("%d
    ", ans);
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    Angular7 表单
    使用Angular2的Http发送AJAX请求
    Nginx配置SSL证书实现https访问「浏览器未认证」
    详解 Nginx如何配置Web服务器
    前后端分离不可缺少的神器 NGINX
    程序员的快速开发框架:Github上 10 大优秀的开源后台控制面板
    腾讯出品的一个超棒的 Android UI 库
    Vue 旅游网首页开发1-工具安装及码云使用
    Angular routing生成路由和路由的跳转
    Angular 父子组件传值
  • 原文地址:https://www.cnblogs.com/cxhscst2/p/7576599.html
Copyright © 2011-2022 走看看