[BZOJ 1567] Blue Mary的战役地图

Link:

BZOJ 1567 传送门

Solution:

矩阵Hash/二维$Hash$模板题

涉及到需要快速查询、匹配的题目,考虑直接上$Hash$

 

矩阵$Hash$其实就是每行先各$Hash$一次,对于$x~x+l-1$行取出$y~y+l-1$列的$Hash$值再进行一次$Hash$即可

取出$l~r$的$Hash$值的方法:$Hash[j]-Hash[i-1]*base^{j-i+1}$

注意横竖两次$Hash$乘数要不同!否则碰撞概率极高

 

Tip: 判断一个数是否在有序序列中的方式:$*lower\_ bound(begin,end,now)==now$

Code:

#include <bits/stdc++.h>

using namespace std;
typedef unsigned long long ull;
const int MAXN=55;
const ull hsn1=2333333,hsn2=1234567;
int n,dat[2][MAXN][MAXN];
ull pre[MAXN],hs[2][MAXN][MAXN],t[MAXN*MAXN];

ull cal(int k,int x,int y,int l)
{
    ull ret=1;
    for(int i=x;i<=x+l-1;i++)
        ret=ret*hsn2+hs[k][i][y+l-1]-hs[k][i][y-1]*pre[l];
    return ret;
}

bool check(int x)
{
    int cnt=0;
    for(int i=1;i<=n-x+1;i++) for(int j=1;j<=n-x+1;j++)
        t[++cnt]=cal(0,i,j,x);
    sort(t+1,t+cnt+1);
    for(int i=1;i<=n-x+1;i++) for(int j=1;j<=n-x+1;j++)
    {
        ull cur=cal(1,i,j,x);
        if(*lower_bound(t+1,t+cnt+1,cur)==cur)
            return true;
    }
    return false;
}

int main()
{
    scanf("%d",&n);
    for (int k=0;k<2;k++) for(int i=1;i<=n;i++) for(int j=1;j<=n;j++)
        scanf("%d",&dat[k][i][j]);
    for(int k=0;k<2;k++)
        for(int i=1;i<=n;i++)
        {
            hs[k][i][0]=1;
            for(int j=1;j<=n;j++) 
                hs[k][i][j]=hs[k][i][j-1]*hsn1+dat[k][i][j];
        }
    
    pre[0]=1;for(int i=1;i<=50;i++) pre[i]=pre[i-1]*hsn1;
    int l=1,r=n;
    while(l<=r)
    {
        int mid=(l+r)>>1;
        if(check(mid)) l=mid+1;
        else r=mid-1;
    }
    printf("%d",r);
    return 0;
}

 

posted @ 2018-06-27 10:46  NewErA  阅读(225)  评论(0编辑  收藏  举报