Wannafly模拟赛 矩阵 [矩阵hash+二分]

5 篇文章 0 订阅

题意:给出一个n * m的矩阵。让你从中发现一个最大的正方形。使得这样子的正方形在矩阵中出现了至少两次。输出最大正方形的边长。

题解:首先我们如何记录一个矩阵的状态,这时候我们需要用到二维hash。二维hash首先是对行进行hash,然后对列进行再hash。当然,两次hash要用到不一样的质数:

for(int i=1;i<=n;i++)//二维hash 
	for(int j=1;j<=m;j++)
		Hash[i][j]=Hash[i][j-1]*basem+a[i][j];
for(int i=1;i<=m;i++)
	for(int j=1;j<=n;j++)
		Hash[j][i]=Hash[j-1][i]*basen+Hash[j][i]; 
对于确定对角顶点的矩阵,我们可以这样获得这个矩阵的hash值:

ll ha=Hash[i][j]-Hash[i][j-mm]*hashm[mm]-Hash[i-nn][j]*hashn[nn]+Hash[i-nn][j-mm]*hashm[mm]*hashn[nn];

假如暴力所有类型的正方形矩阵,我们要n^3的复杂度,这时候我们可以二分答案,再暴力计算当前答案是否存在就可以得到n^2*logn的复杂度。

AC代码:

#include<stdio.h>  
#include<map>  
#include<queue>  
#include<algorithm> 
#define N 505 
using namespace std;  
typedef long long ll;
map<ll,int>mp;
char a[N][N];
int n,m;
ll Hash[N][N];
ll hashn[N],hashm[N],basen=1e9+7,basem=1e9+9;
bool judge(int len)
{
	for(int i=len;i<=n;i++)
		for(int j=len;j<=m;j++)
		{
			ll ha=Hash[i][j]-Hash[i][j-len]*hashm[len]-Hash[i-len][j]*hashn[len]+Hash[i-len][j-len]*hashm[len]*hashn[len];
			if(mp[ha]==1)return true;
			mp[ha]=1;
		}
	return false;
}
ll b[N*N];
int main()
{
	hashm[0]=hashn[0]=1;
	for(int i=1;i<N;i++)
	{
		hashm[i]=hashm[i-1]*basem;
		hashn[i]=hashn[i-1]*basen;
	}
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",a[i]+1);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
			Hash[i][j]=Hash[i][j-1]*basem+a[i][j];
	for(int i=1;i<=m;i++)
		for(int j=1;j<=n;j++)
			Hash[j][i]=Hash[j-1][i]*basen+Hash[j][i]; 
	int l=1,r=min(n,m);
	while(l<=r)
	{
		mp.clear();
		int mid=l+r>>1;
		if(judge(mid))l=mid+1;
		else r=mid-1;
	}
	printf("%d\n",r);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值