洛谷2177(二维hash)

考虑这是一个0 1矩阵 我们对每一行进行 hash ,再对每一列进行 hash ,取两个不同的 base ,这样可以一定程度上保证 hash 的正确性,由于蒟蒻我比较菜,没有写散列表,只能 RP++RP++ 看有没有重复了,横行 d[i][j]=d[i][j-1]base1+a[i][j]d[i][j]=d[i][j−1]∗base1+a[i][j] ,再考虑竖列 sum[i][j]=sum[i-1][j]*base2+d[i][j]sum[i][j]=sum[i−1][j]∗base2+d[i][j] ,再将矩阵整个旋转 180°,如果一个子正方形旋转前和旋转后的 hash 值相同,则大概率下,这两个矩阵相同。我们枚举方阵的边长(注意不能二分,这玩意坑了我很久,我二分一直 WA ,仔细一想发现如果前面不满足,后面满足的情况也是存在的,不满足单调性),枚举矩阵的点,进行 hash判断,时间复杂度O(N³),下面贴代码

//看了看AC记录,貌似 RANK1 ,比 RANK2 快了差不多10倍?其实这题二进制压缩貌似也可做?不过工程量巨大?不管了, QAQ

// 可能代码略丑,借鉴思路即可。

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef unsigned long long ll;
ll base1=131,base2=233;
ll re(){
    char c=getchar();ll all=0,pd=1;
    for(;c>'9'||c<'0';c=getchar()) if(c=='-') pd=-1;
    while(c>='0'&&c<='9') all=all*10+c-'0',c=getchar();return all*pd;
}const ll N=305;
char s[N];ll a[N][N],d[N][N],sum[N][N],aa[N][N],sum2[N][N],n,m,qpow1[N],qpow2[N];
ll cal(ll x,ll y,ll l,ll type){
    if(type==1) return sum[x][y]-sum[x-l][y]*qpow2[l]-sum[x][y-l]*qpow1[l]+sum[x-l][y-l]*qpow1[l]*qpow2[l];
    y=m+l-y,x=n+l-x;
    return sum2[x][y]-sum2[x-l][y]*qpow2[l]-sum2[x][y-l]*qpow1[l]+sum2[x-l][y-l]*qpow1[l]*qpow2[l];
}
ll work(ll l){
    for(ll i=l;i<=n;i++)
        for(ll j=l;j<=m;j++)
    if(cal(i,j,l,1)==cal(i,j,l,2)) return 1;
    return 0;
}ll ans=0;
int main(){
    n=re(),m=re();
    for(ll i=1;i<=n;i++){
        scanf("%s",s+1);
        for(ll j=1;j<=(ll)strlen(s+1);j++)
            a[i][j]=s[j]-'0';
    }
    qpow1[0]=1;for(int i=1;i<=300;i++) qpow1[i]=qpow1[i-1]*base1;
    qpow2[0]=1;for(int i=1;i<=300;i++) qpow2[i]=qpow2[i-1]*base2;

    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
    d[i][j]=d[i][j-1]*base1+a[i][j];
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
    sum[i][j]=sum[i-1][j]*base2+d[i][j];

    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
            aa[i][j]=a[n-i+1][m-j+1];
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
    d[i][j]=d[i][j-1]*base1+aa[i][j];
    for(ll i=1;i<=n;i++)
        for(ll j=1;j<=m;j++)
    sum2[i][j]=sum2[i-1][j]*base2+d[i][j];

    for(int i=1;i<=max(n,m);i++)
    if(work(i)) ans=i;
    if(ans!=1&&ans!=0)printf("%llu",ans);
    else printf("-1\n");
}
posted @ 2018-08-25 09:23  BLUE_EYE  阅读(234)  评论(0编辑  收藏  举报