牛客 矩阵(二分+二维字符串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; 
}

猜你喜欢

转载自blog.csdn.net/TheWayForDream/article/details/121361549