【牛客 -2A】矩阵(二分,字符串哈希)
                                                            生活随笔
收集整理的這篇文章主要介紹了
                                【牛客 -2A】矩阵(二分,字符串哈希)
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.                        
                                題干:
給出一個(gè)n * m的矩陣。讓你從中發(fā)現(xiàn)一個(gè)最大的正方形。使得這樣子的正方形在矩陣中出現(xiàn)了至少兩次。輸出最大正方形的邊長。
輸入描述:
第一行兩個(gè)整數(shù)n, m代表矩陣的長和寬; 接下來n行,每行m個(gè)字符(小寫字母),表示矩陣;輸出描述:
輸出一個(gè)整數(shù)表示滿足條件的最大正方形的邊長。?
示例1
輸入
復(fù)制
5 10 ljkfghdfas isdfjksiye pgljkijlgp eyisdafdsi lnpglkfkjl輸出
復(fù)制
3備注:
對于30%的數(shù)據(jù),n,m≤100; 對于100%的數(shù)據(jù),n,m≤500;解題報(bào)告:
? ?二分一下矩陣的邊長,然后用字符串哈希判斷兩個(gè)矩陣是否相同就可以,,網(wǎng)絡(luò)上找到一個(gè)map的解法,,但是感覺時(shí)間復(fù)雜度太不穩(wěn)定,好的時(shí)候700ms,差的時(shí)候超時(shí),,于是還是以后用多項(xiàng)式哈希吧。。這兩個(gè)剛學(xué)哈希,,代碼還是不特別美觀、、
AC代碼:
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> #define ll long long #define ull unsigned long long #define pb push_back #define pm make_pair #define fi first #define se second using namespace std; const int MAX = 505; using namespace std; const ll D1=31,D2=131; int n,m; char a[MAX][MAX]; ull pow1[MAX],pow2[MAX],h[MAX][MAX],tmp,tmp2,Hash[MAX*MAX]; bool ok(int x) {memset(h,0,sizeof h);int tot=0;for(int i = 1; i<=n; i++) {ull tmp = 0;for(int j = 1; j<x; j++) h[i][j] = h[i][j-1] * D1 + a[i][j];for(int j = x; j<=m; j++) h[i][j] = h[i][j-1] * D1 + a[i][j] - pow1[x] * a[i][j-x]; // for(int j = 1; j<x; j++) tmp = tmp * D1 + a[i][j]; // for(int j = x; j<=m; j++) h[i][j] = tmp * D1 + a[i][j] - pow1[x] * a[i][j-x] , tmp = h[i][j];}for(int j = x; j<=m; j++) {ull tmp = 0;for(int i = 1; i<x; i++) tmp = tmp*D2 + h[i][j];for(int i = x; i<=n; i++) Hash[++tot] = tmp*D2 + h[i][j] - pow2[x] * h[i-x][j] , tmp = Hash[tot];}sort(Hash+1,Hash+tot+1);for(int i = 1; i<tot; i++) {if(Hash[i] == Hash[i+1]) return 1;}return 0 ; } int main() { // ull qq=1,ww=2; // cout <<qq-ww;scanf("%d%d",&n,&m);for(int i=1; i<=n; i++) {scanf("%s",a[i]+1);for(int j=1; j<=m; j++) {a[i][j]-=('a'-1);}}int l=1,r=min(n,m);int mid = (l+r)>>1;int ans;pow1[0]=pow2[0]=1;for(int i=1; i<=n; i++) pow1[i]=pow1[i-1]*D1;for(int i=1; i<=m; i++) pow2[i]=pow2[i-1]*D2;while(l<=r) {mid=(l+r)>>1;if(ok(mid)) l=mid+1,ans=mid;else r=mid-1; }printf("%d",ans);return 0; }AC代碼2:(map版)(這個(gè)時(shí)不時(shí)會跑個(gè)超時(shí)、。。)
#include<cstdio> #include<iostream> #include<algorithm> #include<queue> #include<map> #include<vector> #include<set> #include<string> #include<cmath> #include<cstring> using namespace std; typedef unsigned long long ull; typedef pair<int,int>P; #define maxn 505 int n,m; char s[maxn][maxn]; ull h[maxn][maxn],b[maxn*maxn],base=10007,hhh[maxn][maxn]; inline int ID(int i,int j) {return (i-1)*m+j; } inline bool check(int mid) {map<ull,int>M;for(int x=1; x<=n-mid+1; x++)for(int y=1; y<=m-mid+1; y++) {int xx=x+mid-1,yy=y+mid-1;ull val=(h[xx][yy]-h[xx][y-1]-h[x-1][yy]+h[x-1][y-1])*b[(n-x)*m+m-y];if(M.find(val)!=M.end())return 1;M[val]=1;}return 0; } int main() {scanf("%d%d",&n,&m);for(int i=1; i<=n; i++)scanf("%s",s[i]+1);b[0]=1;for(int i=1; i<=n; i++)for(int j=1; j<=m; j++) {h[i][j]=h[i][j-1]+b[ID(i,j-1)]*(s[i][j]-'a');b[ID(i,j)]=b[ID(i,j-1)]*base;} // for(int j=1; j<=m; j++) // for(int i=1; i<=n; i++) // h[i][j]+=h[i-1][j];int l=0,r=min(n,m),mid,ans=0;while(l<=r) {mid=(l+r)/2;if(check(mid))ans=mid,l=mid+1;else r=mid-1;}printf("%d\n",ans);return 0; }總結(jié):據(jù)syt表示,哈希題目多半帶個(gè)log,,這次做題果然是,需要比較,所以需要先排序這樣。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的【牛客 -2A】矩阵(二分,字符串哈希)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 【CodeForces - 371D】V
- 下一篇: 经常"咔咔"掰手指 会不会得关节炎?有人
