当前位置: 首页 > news >正文

P4330 [COCI 2006/2007 #1] Debug / P2177 内存杀手

题目描述

中文题面见洛谷P2177。

While debugging a program Mirko noticed that a bug in the program may be linked with the existence of so called square killers in the program memory. The program memory is a matrix composed of R \texttt R R rows and C \texttt C C columns consisting only of zeroes and ones. A square killer is a square submatrix in memory, consisting of more than one character, that, when rotated 180 180 180 degrees looks exactly the same. For example, the following matrix contains 3 3 3 square killers:

在这里插入图片描述
Mirko is wondering if there is a connection between the size of the largest square killer and the bug in the program. Help Mirko by writing a program that, given the layout of the memory, outputs the size of the largest square killer. The size of the square killer is the number of rows (or columns) that the killer consists of. In the example above the killer sizes are 2 2 2, 2 2 2 and 3 3 3, respectively.

输入格式

The first will contain two integers, R \texttt R R and C \texttt C C, smaller than or equal to 300 300 300. The next R \texttt R R lines will each contain C \texttt C C characters (‘ 0 0 0’ or ‘ 1 1 1’) with no spaces.

输出格式

Output the size of the largest killer on a single line, or output - 1 \texttt -1 -1 if there are no square killers.

样例

样例输入1:

3 6
101010
111001
101001

样例输出1:

3

样例输入2:

4 5
10010
01010
10101
01001

样例输出2:

3

样例输入3:

3 3
101
111
100

样例输出3:

-1

数据范围

1 ≤ R,C ≤ 300 1 \le \texttt {R,C} \le 300 1R,C300

题解

题目让我们在一个 R × C \texttt{R} \times \texttt{C} R×C 的矩形中,求一个边长为 k k k 的正方形, k > 1 k > 1 k>1,其本身与旋转 180 ˚ 180\r{} 180˚ 的正方形一样,求最大的 k k k,没有则输出 − 1 -1 1

由于要求最大的边长,所以从 min ⁡ ( R,C ) \min(\texttt{R,C}) min(R,C) 开始枚举边长,一直枚举到 1 1 1,然后在枚举正方形的任意一个端点进行判断。

运用二维哈希,将矩阵本身和旋转 180 ˚ 180\r{} 180˚ 后的矩阵的二维哈希值求出来。对于一个边长为 k k k,右下端点为 i , j i, j i,j,在原矩形中四个端点为 ( i − k + 1 , j − k + 1 ) , ( i − k + 1 , j ) , ( i , j − k + 1 ) , ( i , j ) (i - k + 1, j - k + 1),(i - k + 1,j),(i,j - k + 1),(i,j) (ik+1,jk+1),(ik+1,j),(i,jk+1),(i,j),对应在旋转 180 ˚ 180\r{} 180˚ 后的矩阵上为 ( R − i + 1 , C − j + 1 ) , ( R − i + 1 , C − j + k ) , ( R − i + k , C − j + 1 ) , ( R − i + k , C − j + k ) (R - i + 1,C - j + 1),(R - i + 1, C - j + k),(R - i + k, C - j + 1),(R - i + k, C - j + k) (Ri+1,Cj+1),(Ri+1,Cj+k),(Ri+k,Cj+1),(Ri+k,Cj+k)

哈希预处理时间复杂度为 O ( R ⋅ C ) O(\texttt{R} \cdot \texttt{C}) O(RC),枚举复杂度为 O ( min ⁡ ( R,C ) ⋅ R ⋅ C ) O(\min(\texttt{R,C}) \cdot \texttt{R} \cdot \texttt{C}) O(min(R,C)RC),哈希判断为 O ( 1 ) O(1) O(1),总复杂度为 O ( n 3 ) O(n^3) O(n3),可以通过此题。


如果不会二维哈希,可以去查阅资料,这里简单说一下。

参考一维哈希,前缀和为 h i = h i − 1 × b a s e + a i h_{i} = h_{i - 1} \times base + a_i hi=hi1×base+ai,差分为 S h ( l , r ) = h r − h l − 1 × b a s e r − l + 1 S_h(l, r) = h_r - h_{l - 1} \times base^{r - l + 1} Sh(l,r)=hrhl1×baserl+1

二维哈希同理,可以参考二维前缀和, h i , j = h i − 1 , j + h i , j − 1 − h i − 1 , j − 1 + a i , j h_{i,j} = h_{i - 1, j} + h_{i, j - 1} - h_{i - 1, j - 1} + a_{i, j} hi,j=hi1,j+hi,j1hi1,j1+ai,j,差分为 S h ( l 1 , r 1 , l 2 , r 2 ) = ( h l 2 , r 2 − h l 1 − 1 , r 2 − h l 2 , r 1 − 1 + h l 1 − 1 , r 1 − 1 ) ⋅ ( b a s e 1 l 1 − 1 ) − 1 ⋅ ( b a s e 2 r 1 − 1 ) − 1 S_h(l_1, r_1, l_2, r_2) = (h_{l2, r2} - h_{l1 - 1, r2} - h_{l2, r1 - 1} + h_{l1 - 1, r1 - 1}) \cdot (base1^{l1 - 1})^{-1} \cdot (base2^{r1-1})^{-1} Sh(l1,r1,l2,r2)=(hl2,r2hl11,r2hl2,r11+hl11,r11)(base1l11)1(base2r11)1,乘上的逆元是将矩阵对齐到左上角。但这样的时间复杂度较高,要求逆元,考虑优化。

以各维度到右下角的距离作为 b a s e base base 的指数,从而避免逆元运算。

前缀和: h i , j = h i − 1 , j ⋅ b a s e 1 + h i , j − 1 ⋅ b a s e 2 − h i − 1 , j − 1 ⋅ b a s e 1 ⋅ b a s e 2 + a i , j h_{i, j} = h_{i - 1, j} \cdot base1 + h_{i, j - 1} \cdot base2 - h_{i - 1, j - 1} \cdot base1 \cdot base2 + a_{i, j} hi,j=hi1,jbase1+hi,j1base2hi1,j1base1base2+ai,j
差分: S h ( l 1 , r 1 , l 2 , r 2 ) = h ( l 2 , r 2 ) − h l 2 , r 1 − 1 ⋅ b a s e 2 r 2 − r 1 + 1 − h l 1 − 1 , r 2 ⋅ b a s e 1 l 2 − l 1 + 1 + h l 1 − 1 , r 1 − 1 ⋅ b a s e 1 l 2 − l 1 + 1 ⋅ b a s e 2 r 2 − r 1 + 1 S_h(l_1, r_1, l_2, r_2) = h(l_2, r_2) - h_{l2, r1 - 1} \cdot base2^{r2 - r1 + 1} - h_{l1 - 1, r2} \cdot base1^{l2 - l1 + 1} + h_{l1 - 1, r1 - 1} \cdot base1^{l2 - l1 + 1} \cdot base2^{r2 - r1 + 1} Sh(l1,r1,l2,r2)=h(l2,r2)hl2,r11base2r2r1+1hl11,r2base1l2l1+1+hl11,r11base1l2l1+1base2r2r1+1

具体细节见代码。


const unsigned long long base1 = 1009, base2 = 131;
int n, m;//R,C
int a[2][310][310];//a[0] 为原始矩阵,a[1] 为旋转后的矩阵
unsigned long long fac[2][90010];//fac[0][i] 表示 base1^i,fac[1][i] 表示 base2^i,用于逆元
unsigned long long h[2][310][310];//hash矩阵的值
unsigned long long get_sum(int l1, int r1, int l2, int r2, int i){//计算左上角为 (l1,r1),右下角为 (l2,r2) 的矩阵哈希值
    return h[i][l2][r2] - h[i][l2][r1 - 1] * fac[1][r2 - r1 + 1] - h[i][l1 - 1][r2] * fac[0][l2 - l1 + 1] + h[i][l1 - 1][r1 - 1] * fac[0][l2 - l1 + 1] * fac[1][r2 - r1 + 1];
}
int main(){
	//预处理逆元
    fac[0][0] = fac[1][0] = 1;
    for(int i = 1; i <= 90000; ++ i){
        fac[0][i] = fac[0][i - 1] * base1;
        fac[1][i] = fac[1][i - 1] * base2;
    }
	scanf("%d %d", &n, &m);
	for(int i = 1; i <= n; ++ i){
		for(int j = 1; j <= m; ++ j){
            char x;
            cin >> x;
            a[0][i][j] = x - '0';
		}
	}
	//旋转矩阵
	for(int i = 1; i <= n; ++ i){
		for(int j = 1; j <= m; ++ j){
			a[1][i][j] = a[0][n - i + 1][m - j + 1];
		}
	}
	//求 hash 值
	for(int k = 0; k < 2; ++ k){
		for(int i = 1; i <= n; ++ i){
			for(int j = 1; j <= m; ++ j){
				h[k][i][j] = h[k][i][j - 1] * base2 + h[k][i - 1][j] * base1 - h[k][i - 1][j - 1] * base1 * base2 + a[k][i][j];
			}
		}
	}
    int t = min(n, m);
    //枚举边长和右下端点
    for(int k = t; k > 1; -- k){
        for(int i = k; i <= n; ++ i){
            for(int j = k; j <= m; ++ j){
                if(get_sum(i - k + 1, j - k + 1, i, j, 0) == get_sum(n - i + 1, m - j + 1, n - i + k, m - j + k, 1)){
                    printf("%d", k);
                    return 0;
                }
            }
        }
    }
    printf("-1");
	return 0;
}

相关文章:

  • 使用SQL分析季度畅销书:深入理解窗口函数与分组聚合
  • 数据预处理都做什么,用什么工具
  • MySQL安装MySQL服务时提示Install-Remove of the Service Denied
  • vim常用快捷键
  • 利用Python爬虫按图搜索1688商品(拍立淘):实战案例指南
  • Kafka日志数据深度解析:从基础查看到高级操作全攻略
  • ruby 的安装
  • 闭环和闭环管理是什么?
  • Redis的一些内存优化方案
  • 257. 二叉树的所有路径
  • 一文读懂Ingress-Nginx以及实战教程
  • 词袋模型 (BOW) 解析及代码实战
  • 华为支付-商户基础支付场景准备
  • MongoDB 入门操作指南
  • 有哪些滤波,原理是什么,分别在什么时候用
  • 模糊数学模型:基础概念
  • DeepSeek 助力 Vue 开发:打造丝滑的卡片(Card)
  • 基于SpringBoot+uniapp的在线办公小程序+LW示例参考
  • 2025 docker可视化管理面板DPanel的安装
  • 如何使用CSS画一个三角形,原理是什么?
  • 国内哪个网站做水产比较大/南宁优化网站网络服务
  • asp网站空间申请/精品成品网站1688
  • 做一个像qq空间的网站/郑州粒米seo顾问
  • 英文杭州网站建设/百度关键词怎么排名
  • wordpress的安装教程视频/福州短视频seo公司
  • 英德网站建设/网络营销策略的概念