zoukankan      html  css  js  c++  java
  • BZOJ1414: [ZJOI2009]对称的正方形(二维hash)


    BZOJ1414: [ZJOI2009]对称的正方形##

      Time Limit: 10 Sec
      Memory Limit: 162 MB

    Description###

      Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究。最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵。通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数。 Orez自然很想知道这个数是多少,可是矩阵太大,无法去数。只能请你编个程序来计算出这个数。
     

    Input###

       文件的第一行为两个整数n和m。接下来n行每行包含m个正整数,表示Orez得到的矩阵。
     

    Output###

       文件中仅包含一个整数answer,表示矩阵中有answer个上下左右对称的正方形子矩阵。
     

    Sample Input###

      5 5
      4 2 4 4 4
      3 1 4 4 3
      3 5 3 3 3
      3 1 5 3 3
      4 2 1 2 4
     

    Sample Output###

      27
        

    HINT

      数据范围
      对于30%的数据 n,m≤100
      对于100%的数据 n,m≤1000 ,矩阵中的数的大小≤10^9

    题目地址:BZOJ1414: [ZJOI2009]对称的正方形

    题目大意: 题目很简洁了>_<

    题解:

      据说正解是Manacher
      然而二维 hash 可以过
      现在中间塞 0
      样例变成:
      00000000000
      04020404040
      00000000000
      03010404030
      00000000000
      03050303030
      00000000000
      03010503030
      00000000000
      04020102040
      00000000000
      然后只要每次寻找长度为奇数的正方形就可以了
      每个对称的正方形上下一样左右一样,只枚举i+j为偶数的点 得到的边长除以2就是以这个点为中心的正方形回文子矩阵数量
      只要做三个二维 hash 就可以了
      (三个方向,从左上到右下,右上到左下,左下到右上 就够了不用四个方向
      对于一个找到的正方形只要他在这三个 hash 矩阵中值一样,就是对称的正方形
      然后发现如果枚举正方形的中心点,长度有二分性
      每次二分 judge 一下就可以了
      ubuntu 输入法没有记忆功能,难受的一匹


    AC代码

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define uint unsigned int
    using namespace std;
    const int N=2e3+5,B1=1e5+7,B2=1e5+9;
    int n,m,ans;
    uint p1[N],p2[N],a[N][N],h1[N][N],h2[N][N],h3[N][N];
    inline int read(){
        int x=0;char ch=getchar();
        while(ch<'0'||ch>'9')ch=getchar();
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x;
    }
    bool judge(int x,int y,int l){
        int len=(l<<1)-1;
        uint A,B;
        A=h1[x+l-1][y+l-1]
            -h1[x-l][y+l-1]*p1[len]
            -h1[x+l-1][y-l]*p2[len]
            +h1[x-l][y-l]*p1[len]*p2[len];
        B=h2[x+l-1][y-l+1]
            -h2[x-l][y-l+1]*p1[len]
            -h2[x+l-1][y+l]*p2[len]
            +h2[x-l][y+l]*p1[len]*p2[len];
        if(A!=B)return 0;
        B=h3[x-l+1][y+l-1]
            -h3[x+l][y+l-1]*p1[len]
            -h3[x-l+1][y-l]*p2[len]
            +h3[x+l][y-l]*p1[len]*p2[len];
        if(A!=B)return 0;
        return 1;
    }
    int erfen(int x,int y){
        int l=1,r=min(min(x,n-x+1),min(y,m-y+1)),res=0;
        while(l<=r){
            int mid=(l+r)>>1;
            if(judge(x,y,mid)){
                res=mid;
                l=mid+1;
            }else r=mid-1;
        }
        return res;
    }
    int main(){
        n=read()<<1|1,m=read()<<1|1;
        for(int i=2;i<=n;i+=2)
            for(int j=2;j<=m;j+=2)
                a[i][j]=read();
        p1[0]=1;for(int i=1;i<=n;i++)p1[i]=p1[i-1]*B1;
        p2[0]=1;for(int i=1;i<=m;i++)p2[i]=p2[i-1]*B2;
        memcpy(h1,a,sizeof(a));
        memcpy(h2,a,sizeof(a));
        memcpy(h3,a,sizeof(a));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                h1[i][j]+=h1[i-1][j]*B1;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                h1[i][j]+=h1[i][j-1]*B2;
    
        for(int i=1;i<=n;i++)
            for(int j=m;j>=1;j--)
                h2[i][j]+=h2[i-1][j]*B1;
        for(int i=1;i<=n;i++)
            for(int j=m;j>=1;j--)
                h2[i][j]+=h2[i][j+1]*B2;
    
        for(int i=n;i>=1;i--)
            for(int j=1;j<=m;j++)
                h3[i][j]+=h3[i+1][j]*B1;
        for(int i=n;i>=1;i--)
            for(int j=1;j<=m;j++)
                h3[i][j]+=h3[i][j-1]*B2;
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                if(((i^j^1)&1))ans+=(erfen(i,j)>>1);
        printf("%d
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    html 输入框 只能输入数字 只能输入字母数字 等组合
    element中table高度自适应问题
    设置千分位问题(改变数据结构形式--转成字符串)
    在element的table接受数据设置千分位问题(不改变数据类型)
    element在使用tab页时,echarts只在第一个页面加载(第二个tab页也在默认tab页显示)问题
    css1
    B/S(Web)实时通讯解决方案
    WebRTC介绍及简单应用
    webpack的编译流程
    01 写一个 mySetInterVal(fn, a, b),每次间隔 a,a+b,a+2b 的时间,然后写一个 myClear,停止上面的 mySetInterVal
  • 原文地址:https://www.cnblogs.com/shaokele/p/9630071.html
Copyright © 2011-2022 走看看