• bzoj 1414: [ZJOI2009]对称的正方形


    Description

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

    Input

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

    Output

    文件中仅包含一个整数answer,表示矩阵中有answer个上下左右对称的正方形子矩阵。
     
    hash+二分确定每个中心的最大对称正方形
    #include<cstdio>
    char buf[12000007],*ptr=buf;
    int _(){
        int x=0;
        while(*ptr<48)++ptr;
        while(*ptr>47)x=x*10+*ptr++-48;
        return x;
    }
    typedef unsigned int u32;
    int n,m;
    int a[1007][1007];
    u32 f[3][1007][1007],pp1[1007],pp2[1007];
    long long ans=0;
    const u32 p1=1015415441,p2=1115415451;
    #define F(i,n) for(int i=1;i<=n;++i)
    #define Fd(i,n) for(int i=n;i>=1;--i)
    int min(int a,int b){return a<b?a:b;}
    bool chk(int l1,int r1,int l2,int r2){
        u32 v1=pp1[r1-l1+1];
        u32 v2=pp2[r1-l1+1];
        u32 h0=f[0][r1][r2]-f[0][r1][l2-1]*v2-(f[0][l1-1][r2]-f[0][l1-1][l2-1]*v2)*v1;
        u32 h1=f[1][r1][l2]-f[1][r1][r2+1]*v2-(f[1][l1-1][l2]-f[1][l1-1][r2+1]*v2)*v1;
        if(h0!=h1)return 0;
        u32 h2=f[2][l1][r2]-f[2][l1][l2-1]*v2-(f[2][r1+1][r2]-f[2][r1+1][l2-1]*v2)*v1;
        return h0==h2;
    }
    int main(){
        fread(buf,1,sizeof(buf),stdin);
        n=_(),m=_();
        F(i,n)F(j,m)f[0][i][j]=f[1][i][j]=f[2][i][j]=a[i][j]=_();
        F(i,n){
            F(j,m)f[0][i][j]+=f[0][i][j-1]*p2;
            F(j,m)f[0][i][j]+=f[0][i-1][j]*p1;
        }
        F(i,n){
            Fd(j,m)f[1][i][j]+=f[1][i][j+1]*p2;
            Fd(j,m)f[1][i][j]+=f[1][i-1][j]*p1;
        }
        Fd(i,n){
            F(j,m)f[2][i][j]+=f[2][i][j-1]*p2;
            F(j,m)f[2][i][j]+=f[2][i+1][j]*p1;
        }
        pp1[0]=pp2[0]=1;
        F(i,n)pp1[i]=pp1[i-1]*p1;
        F(i,m)pp2[i]=pp2[i-1]*p2;
        
        F(i,n)F(j,m){
            int L=0,R=min(min(i-1,n-i),min(j-1,m-j)),M=1;
            while(L<R){
                if(chk(i-M,i+M,j-M,j+M))L=M;
                else R=M-1;
                M=L+R+1>>1;
            }
            ans+=L+1;
        }
        F(i,n-1)F(j,m-1)if(a[i][j]==a[i][j+1]&&a[i][j]==a[i+1][j]&&a[i][j]==a[i+1][j+1]){
            int L=0,R=min(min(i-1,n-1-i),min(j-1,m-1-j)),M=1;
            while(L<R){
                if(chk(i-M,i+M+1,j-M,j+M+1))L=M;
                else R=M-1;
                M=L+R+1>>1;
            }
            ans+=L+1;
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    移植thinkPHP的dump()函数
    PHP生成linux命令行进度条
    没有ORM库的时候,通过PDO连接MySQL的方法
    mysql json字符串 解析成对应字段
    linux上安装并启动nginx
    linux上启动redis
    mui的input搜索框里的清除按钮的点击监听事件
    miniui 修改input样式及弹出框按钮文字
    js 删除数组元素的方法
    miniui反选
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7267343.html
Copyright © 2020-2023  润新知