牛客 矩阵(二分+二维字符串hash)

分析:

这道题就是一道二维字符串hash的模板题,学习下二维字符串hash,将图中的每一个子矩阵的hash值预处理出来,然后用二分答案去判断是否存在两个hash值相同的正方形即可.

这里直接给出二维字符串hash计算模板

一维hash是把一个字符串用一个整数表示,二维hash是把一个矩阵用一个整数表示。

void init(){
	p1[0] = p2[0] = 1;
	for(int i=1;i<505;i++){
		p1[i] = p1[i-1]*base1;
		p2[i] = p2[i-1]*base2;
	}
	return ;
}

void get_Hash(){
	//Hash公式 Hash[i][j] = Hash[i][j-1]*base1+Hash[i-1][j]*base2+a[i][j] 
	//先横着Hash 
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		Hash[i][j] = Hash[i][j-1]*base1+s[i][j];
	} 
	//再竖着Hash,此时的hash[i][j]= Hash[i][j-1]*base1+s[i][j]
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		Hash[i][j]+=Hash[i-1][j]*base2;
	} 
}

计算右下角为(x,y),长度为Size正方形的hash值

for(int i=Size;i<=n;i++)
	for(int j=Size;j<=m;j++){
		ll k = Hash[i][j]-Hash[i-Size][j]*p2[Size]-Hash[i][j-Size]*p1[Size];
		k+=Hash[i-Size][j-Size]*p1[Size]*p2[Size];
		mp[k]++;
		if(mp[k]==2) return true;
		//这里的k就是hash值,求法类似于求二维前缀和的方法
	}

AC_Code:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ll;//unsigned long long ll自溢出功能,溢出后对自己取模 
//找一个base1和base2都是相对大的素数,减小hash冲突的概率 
ll base1 = 92083;
ll base2 = 69061;
const int Maxn = 505;
ll p1[Maxn],p2[Maxn];
ll Hash[Maxn][Maxn];
map<ll,ll>mp;
int n,m;
char s[Maxn][Maxn];
void init(){
	p1[0] = p2[0] = 1;
	for(int i=1;i<505;i++){
		p1[i] = p1[i-1]*base1;
		p2[i] = p2[i-1]*base2;
	}
	return ;
}
void get_Hash(){
	//Hash公式 Hash[i][j] = Hash[i][j-1]*base1+Hash[i-1][j]*base2+a[i][j] 
	//先横着Hash 
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		Hash[i][j] = Hash[i][j-1]*base1+s[i][j];
	} 
	//再竖着Hash,此时的hash[i][j]= Hash[i][j-1]*base1+s[i][j]
	for(int i=1;i<=n;i++)
	for(int j=1;j<=m;j++){
		Hash[i][j]+=Hash[i-1][j]*base2;
	} 
}
bool check(int Size){
	mp.clear();
	//这里计算右下角为(x,y)边长为Size的正方形的hash值,类似于二维前缀和 
	for(int i=Size;i<=n;i++)
	for(int j=Size;j<=m;j++){
		ll k = Hash[i][j]-Hash[i-Size][j]*p2[Size]-Hash[i][j-Size]*p1[Size];
		k+=Hash[i-Size][j-Size]*p1[Size]*p2[Size];
		mp[k]++;
		if(mp[k]==2) return true;
	}
	return false;
}
int main(){
	init();
	cin>>n>>m;
    for(int i=1;i<=n;i++){
    	scanf("%s",s[i]+1);
	}
	get_Hash();//一定要放到输入数据后面 
	int l = 1,r = min(n,m);
	int ans = 0;
	while(l<=r){
		int mid = l+r>>1;
		if(check(mid)){
			ans = mid;
			l = mid+1; 
		}
		else r = mid-1;
	}
	cout<<ans<<'\n';
	return 0; 
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值