1. 程式人生 > >[luoguP2601] [ZJOI2009]對稱的正方形(二維Hash + 二分 || Manacher)

[luoguP2601] [ZJOI2009]對稱的正方形(二維Hash + 二分 || Manacher)

getchar() cst ons pro color tar zjoi fine long

傳送門

很蒙蔽,不知道怎麽搞。

網上看題解有說可以哈希+二分搞,也有的人說用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 }
View Code

Manacher的話,學完再搞吧。

[luoguP2601] [ZJOI2009]對稱的正方形(二維Hash + 二分 || Manacher)