BZOJ 1414 ZJOI2009 对称的正方形 Hash+二分

题目大意:求正方形回文子矩阵数量(即左右对称、上下对称的正方形子矩阵)

正解是Manacher……但是Hash+二分是能卡过去的0.0 我太丧病了0.0

首先为了避免边长奇偶性带来的WT要把矩阵扩大二倍 然后样例就变成了这样:

00000000000

04020404040

00000000000

03010404030

00000000000

03050303030

00000000000

03010503030

00000000000

04020102040

00000000000

把这个矩阵从四个角各哈希一遍 对于每个点二分答案 验证时将四个哈希值全都取出来对比即可

然后只枚举i+j为偶数的点 得到的边长除以2就是以这个点为中心的正方形回文子矩阵数量

记得二维哈希的时候横竖的BASE值不能相同 然后这个用unsigned long long是超时的 数据没有特殊构造 所以用unsigned int就能卡过去了

回头学学Manacher……我真是太丧病了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 2020
#define BASE1 999911657
#define BASE2 999911659
using namespace std;
typedef unsigned int ll;
ll sum[4][M][M];
int m,n;
ll ans;
ll power1[M],power2[M];
bool Judge(int x,int y,int l)
{
	ll hash,temp;
	hash=sum[0][x+l-1][y+l-1]
		-sum[0][x-l][y+l-1]*power1[l+l-1]
		-sum[0][x+l-1][y-l]*power2[l+l-1]
		+sum[0][x-l][y-l]*power1[l+l-1]*power2[l+l-1];
	temp=sum[1][x+l-1][y-l+1]
		-sum[1][x-l][y-l+1]*power1[l+l-1]
		-sum[1][x+l-1][y+l]*power2[l+l-1]
		+sum[1][x-l][y+l]*power1[l+l-1]*power2[l+l-1];
	if(temp!=hash)
		return false;
	temp=sum[2][x-l+1][y+l-1]
		-sum[2][x-l+1][y-l]*power2[l+l-1]
		-sum[2][x+l][y+l-1]*power1[l+l-1]
		+sum[2][x+l][y-l]*power1[l+l-1]*power2[l+l-1];
	if(temp!=hash)
		return false;
	temp=sum[3][x-l+1][y-l+1]
		-sum[3][x-l+1][y+l]*power2[l+l-1]
		-sum[3][x+l][y-l+1]*power1[l+l-1]
		+sum[3][x+l][y+l]*power1[l+l-1]*power2[l+l-1];
	if(temp!=hash)
		return false;
	return true;
}
ll Bisection(int x,int y)
{
	int l=1,r=min(min(x,m-x+1),min(y,n-y+1));
	while(l+1<r)
	{
		int mid=l+r>>1;
		if( Judge(x,y,mid) )
			l=mid;
		else
			r=mid;
	}
	if( Judge(x,y,r) )
		return r;
	return l;
}
int main()
{
	#ifdef PoPoQQQ
		freopen("1414.in","r",stdin);
		freopen("1414.out","w",stdout);
	#endif

	int i,j,k,x;
	cin>>m>>n;
	m=m<<1|1;n=n<<1|1;
	for(i=2;i<=m;i+=2)
		for(j=2;j<=n;j+=2)
		{
			scanf("%d",&x);
			for(k=0;k<4;k++)
				sum[k][i][j]=x;
		}
	power1[0]=power2[0]=1;
	for(i=1;i<M;i++)
		power1[i]=power1[i-1]*BASE1,
		power2[i]=power2[i-1]*BASE2;
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
			sum[0][i][j]+=sum[0][i-1][j]*BASE1;
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
			sum[0][i][j]+=sum[0][i][j-1]*BASE2;
	for(i=1;i<=m;i++)
		for(j=n;j;j--)
			sum[1][i][j]+=sum[1][i-1][j]*BASE1;
	for(i=1;i<=m;i++)
		for(j=n;j;j--)
			sum[1][i][j]+=sum[1][i][j+1]*BASE2;
	for(i=m;i;i--)
		for(j=1;j<=n;j++)
			sum[2][i][j]+=sum[2][i+1][j]*BASE1;
	for(i=m;i;i--)
		for(j=1;j<=n;j++)
			sum[2][i][j]+=sum[2][i][j-1]*BASE2;
	for(i=m;i;i--)
		for(j=n;j;j--)
			sum[3][i][j]+=sum[3][i+1][j]*BASE1;
	for(i=m;i;i--)
		for(j=n;j;j--)
			sum[3][i][j]+=sum[3][i][j+1]*BASE2;
	for(i=1;i<=m;i++)
		for(j=1;j<=n;j++)
			if( (i^j^1)&1 )
				ans+=Bisection(i,j)>>1;
	cout<<ans<<endl;
}
时间: 2024-11-01 12:53:05

BZOJ 1414 ZJOI2009 对称的正方形 Hash+二分的相关文章

bzoj 1414: [ZJOI2009]对称的正方形 manacher算法+單調隊列

1414: [ZJOI2009]对称的正方形 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 331  Solved: 149[Submit][Status] Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数. Orez自然很想知道这个数是

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

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

【bzoj 1414】对称的正方形 单调队列+manacher

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

【BZOJ1414/3705】[ZJOI2009]对称的正方形 二分+hash

[BZOJ1414/3705][ZJOI2009]对称的正方形 Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一个奇特的数,就是矩阵中上下对称且左右对称的正方形子矩阵的个数. Orez自然很想知道这个数是多少,可是矩阵太大,无法去数.只能请你编个程序来计算出这个数. Input 文件的第一行为两个整数n和m.接下来n行每行包含m个正整数,表示Or

BZOJ 1014 JSOI2008 火星人prefix Splay+Hash+二分

题目大意:给定一个字符串,提供下列操作: 1.查询从x开始的后缀和从y开始的后缀的最长公共前缀长度 2.将x位置的字符修改为y 3.在x位置的字符后面插入字符y 看到这题一开始我先懵住了...这啥..我第一时间想到的是后缀数据结构 但是不会写 而且后缀数据结构也不支持修改操作 后来无奈找了题解才知道是Hash+二分... 太强大了 Hash+二分打爆一切啊 用Splay维护这个字符串的修改和插入操作 每个节点维护子串的Hash值 判断时二分找到最长公共前缀 不过这道题还有一些注意事项 1.此题不

[luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

传送门 很蒙蔽,不知道怎么搞. 网上看题解有说可以哈希+二分搞,也有的人说用Manacher搞,Manacher是什么鬼?以后再学. 对于这个题,可以从矩阵4个角hash一遍,然后枚举矩阵中的点,再二分半径. 但是得考虑边的长度为奇偶所带来的影响. 比如 1 1 1 1 这个边数为偶数的矩阵显然没法搞. 所以得在矩阵中插入0, 变成 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 具体操作就看代码好了. 然后只枚举 行 + 列 为偶数的点就行.

BZOJ 2565 最长双回文串 Hash+二分

题目大意:给定一个字符串,求一个最长的子串,该字串可以分解为两个回文子串 傻逼的我又忘了Manacher怎么写了= = 无奈Hash+二分吧 首先将字符串用分隔符倍增,然后求出以每个点为中心的最长回文半径 然后考虑两个回文串怎么合并成一个 我们发现图中以i为中心的回文串和以j为中心的回文串合并后长度恰好为(j-i)*2 能合并的前提是以两个点为中心的回文串有交点 那么对于每个j我们要求出有交点的最左侧的i 维护一个后缀min随便搞搞就可以了 #include <cstdio> #include

【BZOJ】1014: [JSOI2008]火星人prefix(splay+hash+二分+lcp)

http://www.lydsy.com/JudgeOnline/problem.php?id=1014 被sb错调哭了QAQ...insert那里..插入到第x个后边...我......写成了第x个前面..........还调了!好!久! QAQ 本题神lcp做法....表示只会sa的height的离线.......这种在线的我就QAQ做个忧伤的表情... 然后膜拜了题解....好神..splay维护区间...hash+二分维护lcp....QAQ似乎是白书上说的么... 但是这种有概率的题这

BZOJ 3790 神奇项链 Hash+二分+树状数组

题目大意:给定一个串,问这个串最少可以由回文串拼接多少次而成(拼接可以重叠) 首先将每两个字符之间插入占位符,然后Hash+二分搞出所有极大回文串(可以用manacher,我不会) 问题转化成了给定一些区间,求最少的能覆盖整个数轴的区间 将所有区间按照某一端点排序 然后上树状数组即可 回头还是去学学manacher吧... #include <cstdio> #include <cstring> #include <iostream> #include <algo