• 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,还有这道题的边界处理也非常巧妙,而且我不知道下次我能不能想到,总之先记住这个套路吧。。。

  • 相关阅读:
    go语言简述
    树莓派基础
    电信专用名词
    无线linux应用及配置--wifi配置
    udev简述
    什么是物联网网关?物联网网关具备什么功能?_转
    FTDI通用转USB芯片简述
    Spring实现文件的上传下载
    (转)JVM——内存管理和垃圾回收
    (转)JVM——自定义类加载器
  • 原文地址:https://www.cnblogs.com/xgtao/p/5997578.html
Copyright © 2020-2023  润新知