您的位置:首页 > 其它

bzoj1414 [ZJOI2009]对称的正方形 && bzoj3705 对称的正方形

2017-01-26 22:05 363 查看
【题意】

n*m矩阵,求上下对称且左右对称的正方形个数

【数据范围】

n<=1000,m<=1000

【思路】

模板题

二分+二维hash

二维hash:类似一维hash,对行列分别设置单位k1、k2

【时间复杂度】

O(n^2 log n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 2010
#define k1 1000003
#define k2 101
using namespace std;

int n, m, map

, now, ans, L, R, mid;
unsigned int s[3]

, b1[N*N], b2[N*N];
//s[0]-->上->下,左->右
//s[1]-->上->下,右->左
//s[2]-->下->上,左->右

inline int read(){
int x=0, f=1; char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1; ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
return x*f;
}

int check(int l1, int r1, int l2, int r2){
int x0, x1, x2;
x0=s[0][r1][r2]-s[0][r1][l2-1]*b2[r2-l2+1]-s[0][l1-1][r2]*b1[r1-l1+1]+s[0][l1-1][l2-1]*b1[r1-l1+1]*b2[r2-l2+1];
x1=s[1][r1][l2]-s[1][r1][r2+1]*b2[r2-l2+1]-s[1][l1-1][l2]*b1[r1-l1+1]+s[1][l1-1][r2+1]*b1[r1-l1+1]*b2[r2-l2+1];
if(x0!=x1)return 0;
x2=s[2][l1][r2]-s[2][l1][l2-1]*b2[r2-l2+1]-s[2][r1+1][r2]*b1[r1-l1+1]+s[2][r1+1][l2-1]*b1[r1-l1+1]*b2[r2-l2+1];
if(x0!=x2)return 0;
return 1;
}

int main(){
n=read(); m=read();
memset(map, 0, sizeof(map));
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)map[i*2-1][j*2-1]=read();
n=n*2-1; m=m*2-1;
b1[0]=1; for(int i=1; i<=n*m; i++)b1[i]=b1[i-1]*k1;
b2[0]=1; for(int i=1; i<=n*m; i++)b2[i]=b2[i-1]*k2;
memset(s, 0, sizeof(s));
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)s[0][i][j]=s[0][i][j-1]*k2+map[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]*k1;
for(int i=1; i<=n; i++)
for(int j=m; j; j--)s[1][i][j]=s[1][i][j+1]*k2+map[i][j];
for(int i=1; i<=n; i++)
for(int j=m; j; j--)s[1][i][j]+=s[1][i-1][j]*k1;
for(int i=n; i; i--)
for(int j=1; j<=m; j++)s[2][i][j]=s[2][i][j-1]*k2+map[i][j];
for(int i=n; i; i--)
for(int j=1; j<=m; j++)s[2][i][j]+=s[2][i+1][j]*k1;
ans=0;
for(int i=1; i<=n; i++)
for(int j=1; j<=m; j++)if((i+j)%2==0){
L=1; R=min(min(i, n-i+1), min(j, m-j+1));
while(L<R){
mid=(L+R)>>1; if(L==R-1)mid++;
if(check(i-mid+1, i+mid-1, j-mid+1, j+mid-1))L=mid; else R=mid-1;
}
if(i&1)ans+=(L+1)/2; else ans+=L/2;
}
printf("%d", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: