牛客网 Wannafly模拟赛 矩阵 二分+hash矩阵

来源:互联网 发布:大数据接入dpi 编辑:程序博客网 时间:2024/06/07 08:13

题目链接


题意:



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



思路:

一开始没想明白二分, 首先判断具有单调性,长度为3的正方形存在,长度为2的也一定存在...如果最大长度为6的存在,而长度为7的一定不存在.

然后就是想怎么去快速判断两个矩阵是否相等啊,肯定是hash了.于是hash我算错了复杂度,其实线性就可以hash矩阵了,我算成n3.还是姿势太少。

     

这里我对每一个位置的字母的贡献都按照 第w个位置(一行一行的 ,从1....n*m最多500*500).base^w来计算.先维护一个二维前缀和(利用容斥原理维护二维前缀和的复杂度是n2,查询任意一个一直长度矩阵的和复杂度也是n2,都利用容斥原理) 

然后二分答案,去check. check的时候发现这样hash的话每个正方形内部从1....s个位置 前一个位置比后一个多乘一个base,但是任意两个矩阵之间是差很多的,这里我们让两个矩阵对应的位置次数对齐即可.

 用了map,hash值不合适被卡常数了,复杂度 n*mlog^2 。把hash值改小才过,

     

700ms+

#include<bits/stdc++.h>using namespace std;const int maxn = 500+10;  typedef unsigned long long ll;  char s[maxn][maxn];int n,m;  ll x[maxn*maxn],h[maxn*maxn];ll f[maxn][maxn];  void Hash(){    memset(f,0,sizeof(f));    h[0]=0;x[0]=1;    int k = 0;    for(int i=1;i<=n;i++)      for(int j=1;j<=m;j++){        ++k;        x[k]=x[k-1]*19;        f[i][j]=f[i-1][j]+f[i][j-1]-f[i-1][j-1]+x[k]*(s[i][j]-'a');    }}map<ll,int>mp;ll tmp ;bool check(int ans){    mp.clear();    for(int i=ans;i<=n;i++){        for(int j=ans;j<=m;j++){            tmp = f[i][j]-f[i-ans][j]-f[i][j-ans]+f[i-ans][j-ans];            tmp = tmp*x[(n-i)*m+m-j];            if(mp.count(tmp)) return true;            mp[tmp]=1;        }    }    return false;}int main(){    while(~scanf("%d%d",&n,&m)){                  for(int i=1;i<=n;i++)        scanf("%s",s[i]+1);                  Hash();                  int l=1,r=min(n,m),ans=0,mid;                  while(l<=r){            mid = r+l >> 1;            if(check(mid)) ans = mid,l=mid+1;            else r=mid-1;        }                  printf("%d\n",ans);    }    return 0;}

 




于是手写一个

70ms+

#include<bits/stdc++.h>using namespace std;typedef unsigned long long ull;const ull base=123;const int maxn=4e5+10;const int hashh= 1e6+10;char s[511][511];ull num[511*511],f[511][511];int n,m; struct hashmap{ull a[maxn];int head[hashh];int nxt[maxn];int siz;void init(){memset(head,-1,sizeof head);siz = 0;}bool find(ull val){int tmp = (val % hashh + hashh) % hashh;for(int i = head[tmp];i!=-1;i = nxt[i]){if(val == a[i]) return true;}return false;}void add(ull val){int tmp = (val % hashh + hashh) % hashh;if(find(val)) return ;a[siz] = val;nxt[siz] = head[tmp];//令next指向-1;head[tmp] = siz++; }}Hash;void init(){memset(f,0,sizeof f);num[0]=1;int cnt = 0;for(int i = 1; i <= n;i++) for(int j = 1;j <= m;j++) { cnt++; num[cnt] = num[cnt-1]*base; f[i][j] = f[i-1][j] + f[i][j-1] -f[i-1][j-1] + (s[i][j]-'0')*num[cnt]; } return ;}bool check(int x){Hash.init();for(int i = x;i <= n;i++) for(int j = x;j <= m;j++) { ull tmp = f[i][j] - f[i][j - x] - f[i - x][j] + f[i - x][j - x]; tmp = tmp * num[(n - i) * m + m - j]; if(Hash.find(tmp) == true) return true; Hash.add(tmp); } return false;}int main(){while(~scanf("%d %d",&n,&m)){for(int i = 1;i <= n;i++) scanf("%s",s[i]+1);init();int l = 1,r=min(n,m),mid,ans = -1;while(l<=r){mid = (l + r) >> 1;if(check(mid))l = mid + 1,ans = mid;elser = mid - 1;}printf("%d\n",ans);}return 0;}

原创粉丝点击