[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

具体操作就看代码好了。

然后只枚举 行 + 列 为偶数的点就行。

注意 用 unsigned long long 会超时和超空间,数据允许用 unsigned int

——代码

  1 #include <cstdio>
  2 #include <iostream>
  3 #define UI unsigned int
  4
  5 const int MAXN = 2010, bs1 = 19260817, bs2 = 20011001;
  6 int n, m, ans;
  7 UI sum[4][MAXN][MAXN], base1[MAXN], base2[MAXN];
  8
  9 inline int read()
 10 {
 11     int x = 0, f = 1;
 12     char ch = getchar();
 13     for(; !isdigit(ch); ch = getchar()) if(ch == ‘-‘) f = -1;
 14     for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - ‘0‘;
 15     return x * f;
 16 }
 17
 18 inline int min(int x, int y)
 19 {
 20     return x < y ? x : y;
 21 }
 22
 23 inline bool pd(int x, int y, int l)
 24 {
 25     UI t, h;
 26     h = sum[0][x + l - 1][y + l - 1]
 27       -    sum[0][x - l][y + l - 1] * base1[l + l - 1]
 28       - sum[0][x + l - 1][y - l] * base2[l + l - 1]
 29       + sum[0][x - l][y - l] * base1[l + l - 1] * base2[l + l - 1];
 30     t = sum[1][x + l - 1][y - l + 1]
 31       - sum[1][x - l][y - l + 1] * base1[l + l - 1]
 32       - sum[1][x + l - 1][y + l] * base2[l + l - 1]
 33       + sum[1][x - l][y + l] * base1[l + l - 1] * base2[l + l - 1];
 34     if(h ^ t) return 0;
 35     t = sum[2][x - l + 1][y + l - 1]
 36       - sum[2][x + l][y + l - 1] * base1[l + l - 1]
 37       - sum[2][x - l + 1][y - l] * base2[l + l - 1]
 38       + sum[2][x + l][y - l] * base1[l + l - 1] * base2[l + l - 1];
 39     if(h ^ t) return 0;
 40     t = sum[3][x - l + 1][y - l + 1]
 41       - sum[3][x + l][y - l + 1] * base1[l + l - 1]
 42       - sum[3][x - l + 1][y + l] * base2[l + l - 1]
 43       + sum[3][x + l][y + l] * base1[l + l - 1] * base2[l + l - 1];
 44     if(h ^ t) return 0;
 45     return 1;
 46 }
 47
 48 inline int work(int i, int j)
 49 {
 50     int mid, s = 0, x = 1, y = min(min(i, n - i + 1), min(j, m - j + 1));//二分半径
 51     while(x <= y)
 52     {
 53         mid = (x + y) >> 1;
 54         if(pd(i, j, mid)) s = mid, x = mid + 1;
 55         else y = mid - 1;
 56     }
 57     return s;
 58 }
 59
 60 int main()
 61 {
 62     int i, j, k, x;
 63     n = read();
 64     m = read();
 65     n = n << 1 | 1;
 66     m = m << 1 | 1;
 67     for(i = 2; i <= n; i += 2)
 68         for(j = 2; j <= m; j += 2)
 69         {
 70             x = read();
 71             for(k = 0; k < 4; k++) sum[k][i][j] = x;
 72         }
 73     base1[0] = base2[0] = 1;
 74     for(i = 1; i <= n; i++) base1[i] = base1[i - 1] * bs1;
 75     for(i = 1; i <= m; i++) base2[i] = base2[i - 1] * bs2;
 76     for(i = 1; i <= n; i++)
 77         for(j = 1; j <= m; j++)
 78             sum[0][i][j] += sum[0][i - 1][j] * bs1;
 79     for(i = 1; i <= n; i++)
 80         for(j = 1; j <= m; j++)
 81             sum[0][i][j] += sum[0][i][j - 1] * bs2;
 82     for(i = 1; i <= n; i++)
 83         for(j = m; j; j--)
 84             sum[1][i][j] += sum[1][i - 1][j] * bs1;
 85     for(i = 1; i <= n; i++)
 86         for(j = m; j; j--)
 87             sum[1][i][j] += sum[1][i][j + 1] * bs2;
 88     for(i = n; i; i--)
 89         for(j = 1; j <= m; j++)
 90             sum[2][i][j] += sum[2][i + 1][j] * bs1;
 91     for(i = n; i; i--)
 92         for(j = 1; j <= m; j++)
 93             sum[2][i][j] += sum[2][i][j - 1] * bs2;
 94     for(i = n; i; i--)
 95         for(j = m; j; j--)
 96             sum[3][i][j] += sum[3][i + 1][j] * bs1;
 97     for(i = n; i; i--)
 98         for(j = m; j; j--)
 99             sum[3][i][j] += sum[3][i][j + 1] * bs2;
100     for(i = 1; i <= n; i++)
101         for(j = 1; j <= m; j++)
102             if((i ^ j ^ 1) & 1)
103                 ans += work(i, j) >> 1;
104     printf("%d\n", ans);
105     return 0;
106 }

Manacher的话,学完再搞吧。

时间: 2024-10-12 03:53:33

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

BZOJ 1567 Blue Mary的战役地图(二维hash+二分)

题意: 求两个矩形最大公共子正方形.(n<=50) 范围这么小可以枚举子正方形的边长.那么可以对这个矩形进行二维hash,就可以在O(1)的时候求出任意子矩形的hash值.然后判断这些正方形的hash值有没有相同的 部分就行了.可以用二分来判断. 需要注意的是行和列乘的hash种子值需要不同的质数,否则可能出现冲突. 时间复杂度O(n^3logn). # include <cstdio> # include <cstring> # include <cstdlib>

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

题目大意:求正方形回文子矩阵数量(即左右对称.上下对称的正方形子矩阵) 正解是Manacher--但是Hash+二分是能卡过去的0.0 我太丧病了0.0 首先为了避免边长奇偶性带来的WT要把矩阵扩大二倍 然后样例就变成了这样: 00000000000 04020404040 00000000000 03010404030 00000000000 03050303030 00000000000 03010503030 00000000000 04020102040 00000000000 把这个矩

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

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

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自然很想知道这个数是

URAL 1486 Equal Squares 二维Hash

Hash在信息学竞赛中的一类应用 论文中的第一道例题,关于二维hash的一些处理方法和小技巧 通过RK法计算hash值如果不取模的话可以O(n)预处理,然后O(1)得到任意一个字串的hash值 得到任意子串的hash值的时候不能用除和取模运算了,显然是错的 二维hash如果使用RK法每一次的p值必须不一样 如果不能确定hash值一定不是唯一的,可以计算一个用来确定pos 的hash值和一个用来确定值的hash值 代码写的相当挫,不忍直视 #include <cstdio> #include &

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

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

BZOJ 2462 BeiJing 2011 矩阵模板 二维hash

题目大意:给出一个m*n的由01组成的矩阵,下面有q个询问,查询矩阵中存不存在大小为k*l的子矩阵. 思路:二维hash.我们先把大矩阵hash,然后把所有可能的k*l的子矩阵都插到哈希表里,然后只要对于每个询问hash一下看哈希表中是否存在. 值得一提的是,这个题只需要输出10个1就可以AC了.. CODE: #include <cstdio> #include <bitset> #include <cstring> #include <iostream>

【bzoj1047】[HAOI2007]理想的正方形 二维RMQ

题目描述 有一个a*b的整数组成的矩阵,现请你从中找出一个n*n的正方形区域,使得该区域所有数中的最大值和最小值的差最小. 输入 第一行为3个整数,分别表示a,b,n的值第二行至第a+1行每行为b个非负整数,表示矩阵中相应位置上的数.每行相邻两数之间用一空格分隔.100%的数据2<=a,b<=1000,n<=a,n<=b,n<=1000 输出 仅一个整数,为a*b矩阵中所有“n*n正方形区域中的最大整数和最小整数的差值”的最小值. 样例输入 5 4 2 1 2 5 6 0 1

[BZOJ 1047][HAOI 2007]理想的正方形(二维滑动窗口+单调队列)

题目链接:http://www.lydsy.com:808/JudgeOnline/problem.php?id=1047 思路:裸的二维上的滑动窗口问题,可以借鉴一维滑动窗口的思路.首先预处理出每一列j的.以第i行元素为结尾.长度为n的区间的最大值maxv[i][j].最小值minv[i][j],然后再搞每一行,求出以每一行i结尾.行标上长度为n的区间.以第j列结尾.列标上长度为n的区间得到的二维区间最大值与最小值之差,遍历每一行得到这个差的最小值即为答案. #include <iostrea