[Ybtoj Chapter 7 Example 3] Symmetrical square [Hash]

Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here


Problem-solving ideas

This question is actually similar to the previous question, but it is two-dimensional.
We must find the symmetry axis of the square first, but this is not easy to handle, so we can first make the squares symmetrical left and right and symmetrical up and down. This requires two-dimensional Hash to improve efficiency. The specific processing is similar to the two-dimensional prefix and the columns are done separately. The same is true for flipping squares. When judging symmetry, you only need to judge whether the three squares are the same.

Note that when enumerating the center point, the parity situation should be discussed separately:

  • For a square with an odd length, use a grid (a 1 ∗ 1 1 ∗ 11 1 square) is the farthest length of the center bisection that meets the conditions. .

  • For a square with an even length, take the grid point (that is, a point) as the center to divide the farthest length that meets the condition. .

PS: add n ∗ mn∗m at the endn m because each1 ∗ 1 1 ∗ 11 1 grid is also regarded as a square.


Code

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iomanip>
#include <cmath>
using namespace std;

typedef unsigned long long ull;

ull p1=131,p2=313;
ull g[1010][1010],xturn[1010][1010],yturn[1010][1010];
int ans,n,m,a[1010][1010];

struct c {
    
    
	ull x,y;
} base[1010];

void yu()
{
    
    
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=m; j++)
			xturn[n-i+1][j]=yturn[i][m-j+1]=a[i][j];
	}
}

void hash()//二维Hash
{
    
    
	base[0].x=1,base[0].y=1;
	for(int i=1; i<=max(n,m); i++) {
    
    
		base[i].x=base[i-1].x*p1;
		base[i].y=base[i-1].y*p2;
	}
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=m; j++) {
    
    
			a[i][j]+=a[i-1][j]*p1;
			xturn[i][j]+=xturn[i-1][j]*p1;
			yturn[i][j]+=yturn[i-1][j]*p1;
		}
	}
	for(int i=1; i<=n; i++) {
    
    
		for(int j=1; j<=m; j++) {
    
    
			a[i][j]+=a[i][j-1]*p2;
			xturn[i][j]+=xturn[i][j-1]*p2;
			yturn[i][j]+=yturn[i][j-1]*p2;
		}
	}
}

bool check(int x,int y,int len)
{
    
    
	int v1,v2,v3,y1,x1;
	if(x<len||x>n||y<len||y>m) return 0;
	v1=a[x][y]-a[x-len][y]*base[len].x-a[x][y-len]*base[len].y+a[x-len][y-len]*base[len].y*base[len].x;
	x1=n-(x-len);//上下翻转
	v2=xturn[x1][y]-xturn[x1-len][y]*base[len].x-xturn[x1][y-len]*base[len].y+xturn[x1-len][y-len]*base[len].y*base[len].x;
	y1=m-(y-len);//左右翻转
	v3=yturn[x][y1]-yturn[x-len][y1]*base[len].x-yturn[x][y1-len]*base[len].y+yturn[x-len][y1-len]*base[len].y*base[len].x;
	if(v1==v2&&v2==v3)
		return 1;
	else return 0;
}
void work()
{
    
    
	int t=0,l=0,r=max(n,m)+1,mid=0,x,y;
	//长度为奇数
	for(int i=1; i<n; i++) {
    
    //枚举中心点
		for(int j=1; j<m; j++) {
    
    
			t=0,l=0,r=max(n,m)+1,mid=0;
			while(l<r) {
    
    //二分边长
				mid=(l+r+1)>>1;
				x=mid+i,y=mid+j;//右下角
				if(check(x,y,mid*2)) {
    
    
					t=mid;
					l=mid;
				}
				else r=mid-1;
			}
			ans+=t;
		}
	}
	//长度为奇数
	for(int i=1; i<=n; i++) {
    
    //枚举中心点
		for(int j=1; j<=m; j++) {
    
    
			t=0,l=0,r=max(n,m)+1,mid=0;
			while(l<r) {
    
    
				mid=(l+r+1)>>1;//二分边长
				x=mid+i,y=mid+j;//右下角
				if(check(x,y,mid*2+1)) {
    
    
					t=mid;
					l=mid;
				}
				else r=mid-1;
			}
			ans+=t;
		}
	}
	
}

int main()
{
    
    
	scanf("%d%d",&n,&m);
	for(int i=1; i<=n; i++)
		for(int j=1; j<=m; j++)
			scanf("%d",&a[i][j]);
	yu();
	hash();
	work();
	ans+=m*n;
	printf("%d",ans);
}

/*
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 
*/

Guess you like

Origin blog.csdn.net/kejin2019/article/details/113178678