• 【BZOJ1414】[ZJOI2009]对称的正方形(哈希)


    【BZOJ1414】[ZJOI2009]对称的正方形(哈希)

    题面

    BZOJ
    洛谷

    题解

    深思熟虑一波,发现一个矩阵如果左右对称的话,那么它每行都是一个回文串,同理,如果上下对称的话,那么每列都是一个回文串。既然每行每列都是一个回文串,那么我们把它中心对称一下它还是一个回文串,妙蛙。
    我们在矩阵中间补上(0),这样子就有回文中心了,对于每一个中心算算它往左右能够拓展的最大回文串的长度,然后二分计算一下能够得到的最大矩阵就好了。
    至于哈希什么的,自己随便YY一下吧,我自己写半天不会,直接照着别人的写了一遍额。。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define uint unsigned int
    #define MAX 2020
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    const uint base1=19260817,base2=233;
    int n,m,g[MAX][MAX],ans,tot;
    uint pw1[MAX*MAX],pw2[MAX*MAX],s[3][MAX][MAX];
    bool check(int l1,int r1,int l2,int r2)
    {
    	int len1=r1-l1+1,len2=r2-l2+1;
    	int s0=s[0][r1][r2]-s[0][r1][l2-1]*pw2[len2]-s[0][l1-1][r2]*pw1[len1]+s[0][l1-1][l2-1]*pw1[len1]*pw2[len2];
    	int s1=s[1][r1][l2]-s[1][r1][r2+1]*pw2[len2]-s[1][l1-1][l2]*pw1[len1]+s[1][l1-1][r2+1]*pw1[len1]*pw2[len2];
    	int s2=s[2][l1][r2]-s[2][l1][l2-1]*pw2[len2]-s[2][r1+1][r2]*pw1[len1]+s[2][r1+1][l2-1]*pw1[len1]*pw2[len2];
    	if(s0!=s1||s0!=s2||s1!=s2)return false;
    	return true;
    }
    int main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			g[i*2-1][j*2-1]=read();
    	n=n*2-1,m=m*2-1;tot=n*m;pw1[0]=pw2[0]=1;
    	for(int i=1;i<=tot;++i)pw1[i]=pw1[i-1]*base1;
    	for(int i=1;i<=tot;++i)pw2[i]=pw2[i-1]*base2;
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			s[0][i][j]=s[0][i][j-1]*base2+g[i][j];
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			s[0][i][j]+=s[0][i-1][j]*base1;
    	for(int i=1;i<=n;++i)
    		for(int j=m;j;--j)
    			s[1][i][j]=s[1][i][j+1]*base2+g[i][j];
    	for(int i=1;i<=n;++i)
    		for(int j=m;j;--j)
    			s[1][i][j]+=s[1][i-1][j]*base1;
    	for(int i=n;i;--i)
    		for(int j=1;j<=m;++j)
    			s[2][i][j]=s[2][i][j-1]*base2+g[i][j];
    	for(int i=n;i;--i)
    		for(int j=1;j<=m;++j)
    			s[2][i][j]+=s[2][i+1][j]*base1;
    	for(int i=1;i<=n;++i)
    		for(int j=1;j<=m;++j)
    			if(!((i+j)&1))
    			{
    				int l=1,r=min(min(i,n-i+1),min(j,m-j+1)),ret=0;
    				while(l<=r)
    				{
    					int mid=(l+r)>>1;
    					if(check(i-mid+1,i+mid-1,j-mid+1,j+mid-1))ret=mid,l=mid+1;
    					else r=mid-1;
    				}
    				ans+=(ret+(i&1))>>1;
    			}
    	printf("%d
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    触发器trigger
    VS UFT-8 保存该文件将不会保留原始内容
    SQL SERVER 单个用户模式
    vue functional函数式组件
    一维数组转树形结构
    题解 P1081 【开车旅行】
    题解 P5022 【旅行】
    题解 P2296 【寻找道路】
    题解 P2052 【[NOI2011]道路修建】
    题解 P2342 【叠积木】
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9757385.html
Copyright © 2020-2023  润新知