
YbtOJ hash和hash表课堂过关 例3 对称正方形【hash】【二分】
发布日期:2021-05-07 13:10:04
浏览次数:21
分类:技术文章
本文共 1871 字,大约阅读时间需要 6 分钟。
题目大意
给出一个 n × m n\times m n×m 的矩阵,求矩阵中上下左右对称的正方形子矩阵的个数。
思路
首先这道题暴力去搞肯定会超时,
因为主要是枚举和判断两大部分耗时,所以想到了用二维哈希去做。 此题需要寻找上下左右对称的正方形子矩阵,所以要哈希三次, 分别是原矩阵,上下颠倒的矩阵和左右颠倒的矩阵。 达到 O ( 1 ) O(1) O(1) 的判断复杂度后枚举还是会超时 ( O ( n 3 ) O(n^3) O(n3) 的复杂度),因此考虑优化掉一个 n n n。 回到暴力,一般的暴力都是枚举每一个点,然后从枚举到的点发散判断有否符合条件的矩阵, 发现可以用二分来优化发散步骤的时间,最后时间复杂度是 O ( n 2 log 2 n ) O(n^2\log_2{n}) O(n2log2n)。大体思路解决后,思考怎样发散。
我的思路非常清奇,枚举矩阵右下角的点来做, 可是这样不能满足二分到的范围以内都是上下左右对称的正方形子矩阵啊? 所以需要由右下角的点把二分范围扩大一倍来作判断条件,以中心点为中心。 以此来确保计算的正确性。 其实也就是由右下角的点来确定中心点,异曲同工。判断部分就是把构造出的三个哈希矩阵直接对比(当然是数值的比较),这里不再赘述。
二分要分奇偶,因为奇数和偶数有统计上的差异。
代码
#include#include #include using namespace std;unsigned long long a[1010][1010],b[1010][1010],c[1010][1010];unsigned long long f1[1000010],f2[1000010];int n,m,ans;bool check(int mid,int i,int j){ if(i-mid<0||j-mid<0||i>n||j>m||i<0) return 0; int a1=a[i][j]-a[i-mid][j]*f2[mid]-a[i][j-mid]*f1[mid]+a[i-mid][j-mid]*f1[mid]*f2[mid]; int bx=n-(i-mid),by=m-(j-mid); int b1=b[bx][j]-b[bx-mid][j]*f2[mid]-b[bx][j-mid]*f1[mid]+b[bx-mid][j-mid]*f1[mid]*f2[mid]; int c1=c[i][by]-c[i-mid][by]*f2[mid]-c[i][by-mid]*f1[mid]+c[i-mid][by-mid]*f1[mid]*f2[mid]; //cout< <<" "< <<" "< < >n>>m; f1[0]=1ull,f2[0]=1ull; for(int i=1; i<=max(n,m); i++) f1[i]=f1[i-1]*1000000009ull,f2[i]=f2[i-1]*1000000007ull; for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { scanf("%ulld",&a[i][j]); c[i][m-j+1]=a[i][j]; //左右颠倒 b[n-i+1][j]=a[i][j]; //上下颠倒 //(不明白的手推一下) } yhash(); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { int l=0,r=min(i,j)+1,mid=0,maxx=1; while(l<=r)//奇数 { mid=(l+r)/2; if(check(mid*2-1,i+mid,j+mid)) //扩大到以中心点为中心 l=mid+1,maxx=max(mid*2-1,maxx); else r=mid-1; } ans=ans+(maxx+1)/2; maxx=0; l=0,r=min(i,j); while(l<=r) //偶数 { mid=(l+r)/2; if(check(mid*2,i+mid,j+mid)) //同上 l=mid+1,maxx=max(mid*2,maxx); else r=mid-1; } ans=ans+(maxx+1)/2; } cout<
发表评论
最新留言
能坚持,总会有不一样的收获!
[***.219.124.196]2025年03月27日 07时37分55秒
关于作者

喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
BST中某一层的所有节点(宽度优先搜索)
2019-03-04
广度优先搜索
2019-03-04
对于递归的理解
2019-03-04
二分查找(递归)
2019-03-04
猜字母
2019-03-04
奇怪的分式(枚举 + 判断)
2019-03-04
Linux网络环境配置(设置ip地址)
2019-03-04
Idea使用Spring Initializr来快速创建springboot项目
2019-03-04
C++邻接表存储图的深度优先搜索
2019-03-04
C++实现Dijkstra算法(单源路径最短算法)
2019-03-04
Dijkstra算法的总结
2019-03-04
前后端通信问题 —— SpringBoot+LayUI
2019-03-04
ubuntu中安装scikit-learn
2019-03-04
Ubuntu2004 向日葵安装笔记
2019-03-04
Ubuntu 安装后无法正常打开——进入grub安全命令行模式
2019-03-04
C/C++ new和delete使用注意事项
2019-03-04
Jmeter (一) ----环境搭建
2019-03-04
性能调优优化思路
2019-03-04
CodeBase(四)项目总结
2019-03-04