• 理想正方形 题解


    先言

    若不是看了题解,我倒还真不认为是单调队列优化 (DP) , 关于正解的话,不清楚,但是这道题 (RMQ) , 线段树 + (O_2) 或者 单调队列优化都可以过,(笔者没有挨个实现)

    description

    在一个 (n imes m) 的矩阵中,找出一个 (k imes k) 的一个正方形,并使取得的正方形的极值差最小 。 (n , m leq 10^3 , k leq 100)

    solution

    更优质解答 : link

    首先这道题是有一个很朴素的写法 :
    以最大值为例 :

    • (Max_{i,j,k}) 表示以 (i,j) 节点为左上角,边长为 (k) 的最大值

    (Max_{i,,j,k} = max(Max_{i,j,k - 1} , Max_{i + 1 , j + 1 , k - 1} , Max_{i + 1 , j , k - 1} , Max_{i , j + 1 , k - 1}))

    分别对应着:

    • 我们可以继续扩展当前的这个矩形 (Max_{i,j,k - 1})
    • 我们可以继续将左端点向右下平移,给当前矩形增加一行和一列的扩展空间 : (Max_{i + 1 , j + 1 , k - 1})
    • 向下,向右 , 分别对应着 (Max_{i + 1 , j , k - 1} , Max_{i , j + 1 , k - 1})

    然后我们发现这个是一个 (O(n imes m imes k)) , (k) 直接枚举去掉即可。 不需要 (k) 那一维了。
    (Code)

    for (int k = 2; k <= n; k++)
     for (int i = 1; i < a; i++)
      for (int j = 1; j < b; j++) 
      {
      Max[i][j] = max(a[i][j], max(Max[i+1][j+1], max(Max[i+1][j], Max[i][j+1])));
      Min[i][j] = min(a[i][j], Min(minv[i+1][j+1], min(minv[i+1][j], Min[i][j+1])));
      }
    

    最后取答案的时候,注意节点是从 (0 o n - k + 1) 的,毕竟是左节点,毕竟在这里看了 (20min) 的错误,显然是有发言权的。

    枚举整个矩形这是必不可少的,也就是 (O(n imes m)) 的复杂度是必然少不了的。我们需要简化掉取最小值和最大值,这里用的是单调对列的优化, 我们用对行和列分别建立单调队列,从而在枚举整个矩形的时候直接给整出来就 (OK) 了,这个特别像滑动窗口 。

    说明一下代码内的意思 :
    (1) 的表示最大值 ,带 (2) 表示最小值

    • (f1_{i,j}) 表示 第 (i) 行,第 $j o j + n -1 $ 的最大值,同理 (f2) 为最小值
    • (fm1_{i,j}) 表示以 (i,j) 为开始的左节点的最大值 ,同理 (fm2_{i,j}) 为最小值

    所以我们在实现的时候通过两个循环,分别搞出 (f1,f2)(fm1,fm2) 来, 最后统计答案,注意节点。

    关于这道题的模拟过程,见 : 题解 P2216 【[HAOI2007]理想的正方形】

    Code

    Force

    //这个能拿 70 分,真的是纯暴力, 来口 (O_2)(A) 了。

    /*
     by : Zmonarch
     知识点:
    
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    #include <vector>
    #define int long long
    #define qwq register
    #define inf 2147483647
    const int kmaxn = 1e3 + 10 ;
    const int kmod = 998244353 ;
    namespace Base
    {
    	inline int Min(int a , int b) {return a < b ? a : b ;}
    	inline int Max(int a , int b) {return a < b ? b : a ;}
    	inline int Abs(int a) {return a < 0 ? - a : a ;}
    	inline int Gcd(int a , int b) {return !b ? a : Gcd(b , a % b);}
    }
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ;}
    	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ;}
    	return x * f ;
    }
    int n , m , k ; 
    int a[kmaxn][kmaxn] , f1[kmaxn][kmaxn] , f2[kmaxn][kmaxn] ; 
    signed main()
    {
    	n = read() , m = read() , k = read() ; 
    	for(qwq int i = 1 ; i <= n ; i++) 
    	 for(qwq int j = 1 ; j <= m ; j++) 
    	   f1[i][j] = f2[i][j] = a[i][j] = read() ; 
    	for(qwq int l = 2 ; l <= k ; l++)
    	 for(qwq int i = 1 ; i < n ; i++) 
    	  for(qwq int j = 1 ; j < m ; j++)
    	   {
    	   		f1[i][j] = Base::Max(a[i][j] , Base::Max(f1[i + 1][j + 1] , Base::Max(f1[i + 1][j] , f1[i][j + 1]))) ;
    	   		f2[i][j] = Base::Min(a[i][j] , Base::Min(f2[i + 1][j + 1] , Base::Min(f2[i + 1][j] , f2[i][j + 1]))) ;
    	   }
    	int ans = inf ; 
    	for(qwq int i = 1 ; i <= n - k + 1 ; i++) 
    	 for(qwq int j = 1 ; j <= m - k + 1 ; j++) 
    	  ans = Base::Min(ans , f1[i][j] - f2[i][j]) ; 
    	printf("%lld
    " , ans) ;  
    	return 0 ;
    }
    
    

    单调队列优化 Code

    /*
     by : Zmonarch
     知识点:
    
    */
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cmath>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #include <set>
    #include <map>
    #include <vector>
    #define int long long
    #define inf 2147483647
    #define qwq register
    const int kmaxn = 1e3 + 10 ;
    const int kmod = 998244353 ;
    namespace Base
    {
    	inline int Min(int a , int b) {return a < b ? a : b ;}
    	inline int Max(int a , int b) {return a < b ? b : a ;}
    	inline int Abs(int a) {return a < 0 ? - a : a ;}
    	inline int Gcd(int a , int b) {return !b ? a : Gcd(b , a % b);}
    }
    inline int read()
    {
    	int x = 0 , f = 1 ; char ch = getchar() ;
    	while(!isdigit(ch)) {if(ch == '-') f = - 1 ; ch = getchar() ;}
    	while( isdigit(ch)) {x = x * 10 + ch - '0' ; ch = getchar() ;}
    	return x * f ;
    }
    int n , m , k , l1 , r1 , l2 , r2; 
    int a[kmaxn][kmaxn] , f1[kmaxn][kmaxn] , f2[kmaxn][kmaxn] , q1[kmaxn] , q2[kmaxn] , fm1[kmaxn][kmaxn] , fm2[kmaxn][kmaxn]; 
    signed main()
    {
    	n = read() , m = read() , k = read() ; 
    	for(qwq int i = 1 ; i <= n ; i++)
    	 for(qwq int j = 1 ; j <= m ; j++) 
    	   a[i][j] = read() ;  	
    	for(qwq int i = 1 ; i <= n ; i++) 
    	{
    		l1 = l2 = 1 ; r1 = r2 = 0 ; 
    	 	for(qwq int j = 1 ; j <= m ; j++) 
    	 	{
    	 		while(j - q1[l1] >= k) l1++ ; 
    	 		while(j - q2[l2] >= k) l2++ ; 
    	 		while(l1 <= r1 && a[i][j] >= a[i][q1[r1]]) r1-- ; 
    	 		while(l2 <= r2 && a[i][j] <= a[i][q2[r2]]) r2-- ;
    			q1[++r1] = q2[++r2] = j ; 
    			if(j >= k) 
    			f1[i][j - k + 1] = a[i][q1[l1]] , f2[i][j - k + 1] = a[i][q2[l2]] ;  
    		}
    	}
    	for(qwq int i = 1 ; i <= m - k + 1 ; i++) 
    	{
    		l1 = l2 = 1 ; r1 = r2 = 0 ; 
    		for(qwq int j = 1 ; j <= n ; j++) 
    		{
    			while(j - q1[l1] >= k) l1++ ; 
    			while(j - q2[l2] >= k) l2++ ; 
    			while(l1 <= r1 && f1[j][i] >= f1[q1[r1]][i]) r1-- ; 
    			while(l2 <= r2 && f2[j][i] <= f2[q2[r2]][i]) r2-- ; 
    			q1[++r1] = q2[++r2] = j; 
    			if(j >= k) 
    			fm1[j - k + 1][i] = f1[q1[l1]][i] , fm2[j - k + 1][i] = f2[q2[l2]][i] ;
    		}
    	}
    	int ans = inf ; 
    	for(qwq int i = 1 ; i <= n - k + 1 ; i++) 
    	 for(qwq int  j = 1 ; j <= m - k + 1 ; j++) 
    	   ans = Base::Min(fm1[i][j] - fm2[i][j] , ans) ; 
    	printf("%lld
    " , ans) ; 
    	return 0 ;
    }
    
  • 相关阅读:
    Qt中实现单例模式(SingleTon)
    毕设开发手记(二)
    Qt中由表中单元格的QModelIndex获取Global Pos的正确方法
    Qt的槽可以使用默认参数
    C#结构的了解
    dos命令集江南技术联盟
    C#中的abstract与virtual的用法
    [转]六种删除数据库重复行的方法
    PL/SQL的TO_CHAR()与TO_DATE()
    索引索引索引(转)
  • 原文地址:https://www.cnblogs.com/Zmonarch/p/14600731.html
Copyright © 2020-2023  润新知