zoukankan      html  css  js  c++  java
  • codeforces 713D Animals and Puzzle

    题意:

    给出n * m 的0/1矩阵,然后q组询问,问询问的矩形中包含的全1正方形的最大边长。

    题解:

    首先考虑暴力算法,对于每个询问的矩形,在里面暴力找到全1正方形,现在的问题就是怎么找全1正方形,可以递推实现,dp[i][j]表示以(i, j)作为右下角的全一正方形最长边长。

    dp[i][j] = min (dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1。

    while (T--) {
            int x1, y1, x2, y2;
            scanf ("%d%d%d%d", &x1, &y1, &x2, &y2);
            int ans = 0;
            for (int i = x1; i <= x2; ++i) {
                for (int j = y1; j <= y2; ++j) {
                    int len = dp[i][j];
                    if (i - len + 1 < x1 && j - len + 1 < y1) ans = max (ans, min(i - x1 + 1, j - y1 + 1));
                    else if (j - len + 1 < y1) ans = max (ans, j - y1 + 1);
                    else if (i - len + 1 < x1) ans = max (ans, i - x1 + 1);
                    else ans = max (ans, len);
                }
            }
            cout << ans << endl;
        }
    

      

    现在考虑,对每个询问的两个for循环优化:

    那么现在的问题就是维护一个矩形中最大的dp值是多少,二维线段树?不不不,TLE,复杂度(T * (logn)^3),显然可以用二维ST表

    但是会发现有很多情况会越过边界从而不符合条件,可以二分出矩形的全1正方形的边长,根据定义那么问题就等价于在(x1 + mid - 1, y1 + mid -1)到 (x2, y2)中寻找最大的dp值,就直接拿最大值和二分值比较就好了,就可以不用考虑是否越界的问题了。O(∩_∩)O~

    #include <cstdio>
    #include <algorithm>
    #include <iostream>
    #include <cstring>
    using namespace std;
    
    const int N = 1e3 + 100;
    int n, m, dp[11][11][N][N], T, lg[N];
    
    void BuildSt () {
    	lg[1] = 0;
    	for (int i = 2; i <= 1000; ++i) lg[i] = lg[i >> 1] + 1;
    	for (int x = 1; x <= n; ++x) 
    		for (int i = 1; i <= 10; ++i) 
    			for (int y = 1; y <= m; ++y) 
    				if (y + (1<<i-1) <= m) dp[0][i][x][y] = max (dp[0][i-1][x][y], dp[0][i-1][x][y+(1<<i-1)]);
    	for (int i = 1; i <= 10; ++i) 
    		for (int x = 1; x <= n; ++x) 
    			for (int j = 0; j <= 10; ++j) 
    				for (int y = 1; y <= m; ++y) 
    					if (x + (1<<i-1) <= n) dp[i][j][x][y] = max (dp[i-1][j][x][y], dp[i-1][j][x+(1<<i-1)][y]);
    }
    
    int query (int x1, int y1, int x2, int y2) {
    	int lx = lg[x2 - x1 + 1], ly = lg[y2 - y1 + 1];
    	x2 = x2 - (1 << lx) + 1;
    	y2 = y2 - (1 << ly) + 1;
    	return max (max (dp[lx][ly][x1][y1], dp[lx][ly][x1][y2]), max (dp[lx][ly][x2][y1], dp[lx][ly][x2][y2]));
    }
    
    int main () {
    	scanf ("%d%d", &n, &m);
    	for (int i = 1; i <= n; ++i) {
    		for (int j = 1; j <= m; ++j) {
    			int x;
    			scanf ("%d", &x);
    			if (x == 1)dp[0][0][i][j] = min (dp[0][0][i-1][j], min (dp[0][0][i][j-1], dp[0][0][i-1][j-1])) + 1;	
    		}
    	}
    	BuildSt();
    	scanf ("%d", &T);
    	while (T--) {
    		int x1, y1, x2, y2;
    		scanf ("%d%d%d%d", &x1, &y1, &x2, &y2);
    		int l = 0, r = min (x2 - x1 + 1, y2 - y1 + 1);
    		while (l < r) {
    			int mid = l + r + 1 >> 1;
    			if (query(x1 + mid - 1, y1 + mid - 1, x2, y2) >= mid) l = mid;
    			else r = mid - 1;
    		}
    		cout << l << endl;
    	}
    	return 0;
    }
    

      

    总结:

    蒟蒻涨姿势了~学到了二维的ST,还有这道题的边界处理也非常巧妙,而且我不知道下次我能不能想到,总之先记住这个套路吧。。。

  • 相关阅读:
    树莓派GPIO点亮第一个led
    hexo博客域名重复提交问题
    python与arduino串口通讯对接opencv实现智能物品分拣
    python生成excel文件
    python的机器学习之路
    团队冲刺第三天
    团队冲刺第二天
    团队冲刺第一天
    第二阶段任务认领
    构建之法3
  • 原文地址:https://www.cnblogs.com/xgtao/p/5997578.html
Copyright © 2011-2022 走看看