「JSOI2015」symmetry

传送门

我们先考虑构造出原正方形经过 \(4\) 种轴对称变换以及 \(2\) 种旋转变换之后的正方形都构造出来,然后对所得的 \(7\) 个正方形都跑一遍二维哈希,这样我们就可以通过哈希,在 \(O(n ^ 2)\) 时间内判断原正方形中是否存在某一类型的某一大小的子正方形。

但是如果我们枚举边长,复杂度就会达到 \(O(n ^ 3)\) 级别,显然过不了。

考虑优化:我们发现对于任意一种类型的正方形,它把最外面一圈去掉之后还是满足原来的性质,所以我们可以二分来求。需要注意的是我们不好同时计算奇数边长和偶数边长的正方形,所以要二分两次。

参考代码:

#include <cstdio>
#define rg register
#define file(x) freopen(x".in", "r", stdin), freopen(x".out", "w", stdout)
template < class T > inline T max(T a, T b) { return a > b ? a : b; }
template < class T > inline void read(T& s) {
s = 0; int f = 0; char c = getchar();
while ('0' > c || c > '9') f |= c == '-', c = getchar();
while ('0' <= c && c <= '9') s = s * 10 + c - 48, c = getchar();
s = f ? -s : s;
} typedef unsigned long long ull;
const int _ = 502;
const ull base1 = 19491001, base2 = 19260817;
int n; ull pw1[_], pw2[_], h[7][_][_]; inline ull gethash(int k, int x1, int y1, int x2, int y2) {
int w = x2 - x1 + 1;
return h[k][x2][y2] - h[k][x1 - 1][y2] * pw1[w] - h[k][x2][y1 - 1] * pw2[w] + h[k][x1 - 1][y1 - 1] * pw1[w] * pw2[w];
} inline bool check_90(int x1, int y1, int x2, int y2) {
return gethash(0, x1, y1, x2, y2) == gethash(5, y1, n - x2 + 1, y2, n - x1 + 1);
} inline bool check_180(int x1, int y1, int x2, int y2) {
return gethash(0, x1, y1, x2, y2) == gethash(6, n - x2 + 1, n - y2 + 1, n - x1 + 1, n - y1 + 1);
} inline bool check_diag(int x1, int y1, int x2, int y2) {
return gethash(0, x1, y1, x2, y2) == gethash(1, x1, n - y2 + 1, x2, n - y1 + 1)
|| gethash(0, x1, y1, x2, y2) == gethash(2, n - x2 + 1, y1, n - x1 + 1, y2)
|| gethash(0, x1, y1, x2, y2) == gethash(3, y1, x1, y2, x2)
|| gethash(0, x1, y1, x2, y2) == gethash(4, n - y2 + 1, n - x2 + 1, n - y1 + 1, n - x1 + 1);
} inline bool check_4(int x1, int y1, int x2, int y2) {
return check_180(x1, y1, x2, y2) && check_diag(x1, y1, x2, y2);
} inline bool check_8(int x1, int y1, int x2, int y2) {
return check_90(x1, y1, x2, y2) && check_diag(x1, y1, x2, y2);
} template < class T > inline bool check(T f, int x) {
for (rg int i = x; i <= n; ++i)
for (rg int j = x; j <= n; ++j)
if (f(i - x + 1, j - x + 1, i, j)) return 1;
return 0;
} template < class T > inline int solve(T f) {
int res = 0, l, r, mid;
l = 0, r = (n - 1) >> 1;
while (l < r) {
mid = (l + r + 1) >> 1;
if (check(f, mid << 1 | 1)) l = mid; else r = mid - 1;
}
res = max(res, l << 1 | 1);
l = 1, r = n >> 1;
while (l < r) {
mid = (l + r + 1) >> 1;
if (check(f, mid << 1)) l = mid; else r = mid - 1;
}
res = max(res, l << 1);
return res;
} int main() {
#ifndef ONLINE_JUDGE
file("cpp");
#endif
read(n);
for (rg int i = 1; i <= n; ++i)
for (rg int j = 1; j <= n; ++j) {
scanf("%1d", &h[0][i][j]);
h[1][i][n - j + 1] = h[0][i][j];
h[2][n - i + 1][j] = h[0][i][j];
h[3][j][i] = h[0][i][j];
h[4][n - j + 1][n - i + 1] = h[0][i][j];
h[5][j][n - i + 1] = h[0][i][j];
h[6][n - i + 1][n - j + 1] = h[0][i][j];
}
pw1[0] = 1; for (rg int i = 1; i <= n; ++i) pw1[i] = pw1[i - 1] * base1;
pw2[0] = 1; for (rg int i = 1; i <= n; ++i) pw2[i] = pw2[i - 1] * base2;
for (rg int k = 0; k < 7; ++k) {
for (rg int i = 1; i <= n; ++i) for (rg int j = 1; j <= n; ++j) h[k][i][j] += h[k][i - 1][j] * base1;
for (rg int i = 1; i <= n; ++i) for (rg int j = 1; j <= n; ++j) h[k][i][j] += h[k][i][j - 1] * base2;
}
printf("%d %d %d %d %d\n", solve(check_8), solve(check_90), solve(check_4), solve(check_180), solve(check_diag));
return 0;
}

「JSOI2015」symmetry的更多相关文章

  1. 「JSOI2015」串分割

    「JSOI2015」串分割 传送门 首先我们会有一个贪心的想法:分得越均匀越好,因为长的绝对比短的大. 那么对于最均匀的情况,也就是 \(k | n\) 的情况,我们肯定是通过枚举第一次分割的位置,然 ...

  2. 「JSOI2015」isomorphism

    「JSOI2015」isomorphism 传送门 我们还是考虑树哈希来判同构. 但是我们需要使用一些特殊的手段来特殊对待假节点. 由于是无向树,我们首先求出重心,然后以重心为根跑树哈希. 此处我们不 ...

  3. 「JSOI2015」地铁线路

    「JSOI2015」地铁线路 传送门 第一问很简单:对于每条线路建一个点,然后所有该条线路覆盖的点向它连边,权值为 \(1\) ,然后它向所有线路上的点连边,权值为 \(0\) . 然后,跑一边最短路 ...

  4. 「JSOI2015」染色问题

    「JSOI2015」染色问题 传送门 虽然不是第一反应,不过还是想到了要容斥. 题意转化:需要求满足 \(N + M + C\) 个条件的方案数. 然后我们就枚举三个数 \(i, j, k\) ,表示 ...

  5. 「JSOI2015」圈地

    「JSOI2015」圈地 传送门 显然是最小割. 首先对于所有房子,权值 \(> 0\) 的连边 \(s \to i\) ,权值 \(< 0\) 的连边 \(i \to t\) ,然后对于 ...

  6. 「JSOI2015」最小表示

    「JSOI2015」最小表示 传送门 很显然的一个结论:一条边 \(u \to v\) 能够被删去,当且仅当至少存在一条其它的路径从 \(u\) 通向 \(v\) . 所以我们就建出正反两张图,对每个 ...

  7. 「JSOI2015」套娃

    「JSOI2015」套娃 传送门 考虑贪心. 首先我们假设所有的套娃都互相不套. 然后我们考虑合并两个套娃 \(i\),\(j\) 假设我们把 \(i\) 套到 \(j\) 里面去,那么就可以减少 \ ...

  8. 「JSOI2015」非诚勿扰

    「JSOI2015」非诚勿扰 传送门 我们首先考虑一名女性选中她列表里第 \(x\) 名男性的概率(假设她列表里共有 \(s\) 名男性): \[ P = p \times (1 - p) ^ {x ...

  9. 「JSOI2015」salesman

    「JSOI2015」salesman 传送门 显然我们为了使收益最大化就直接从子树中选大的就好了. 到达次数的限制就是限制了可以选的子树的数量,因为每次回溯上来都会减一次到达次数. 多种方案的判断就是 ...

随机推荐

  1. flask入门(三)

    表单 request.form 能获取POST 请求中提交的表单数据.但是这样不太安全,容易受到恶意攻击.对此,flask有一个flask-wtf扩展,用于避免这一情况 在虚拟环境下用pip inst ...

  2. Date/Math/String对象的函数

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  3. python面试的100题(19)

    61.如何在function里面设置一个全局变量 Python中有局部变量和全局变量,当局部变量名字和全局变量名字重复时,局部变量会覆盖掉全局变量. 如果要给全局变量在一个函数里赋值,必须使用glob ...

  4. rest_framework:响应器(渲染器)

    一.作用: 根据用户的请求url或者用户可接受的类型.筛选出合适的渲染组件 用户请求url: http://127.0.0.1:8000/test/?format=json http://127.0. ...

  5. [Java IO]05_JSON操作

    目录 6.1 JSON 知识背景  6.1.1 JSON 简介  6.1.2 JSON 语法  6.1.3 JSON 的数据结构6.2 Java 中操作 JSON 数据  6.2.1 Jar包下载   ...

  6. OpenGL 编程指南 (2)

    1.OpenGL对共享的边有严格的规定:1)共享边上的像素因为同事被两者所覆盖,因此不可能不受到光照计算的影响: 2)共享边上的像素值,不可能受到多于一个三角形的光照计算的影响. 2.多边形存在正面与 ...

  7. 电脑进不去BIOS解决办法

    把所有外设(主要是硬盘,包括装在主板上的固态硬盘)拆下来,拆下纽扣电池给主板放电,装回纽扣电池,重启F1进入BIOS. 最终查到原因,是固态那里出的问题,固态作为启动硬盘,被自己搞得有问题了,有两个启 ...

  8. Python学习笔记9——异常处理

    处理异常 如果执行到程序中某处抛出了异常,程序就会被终止并退出.你可能会问,那有没有什么办法可以不终止程序,让其照样运行下去呢?答案当然是肯定的,这也就是我们所说的异常处理,通常使用 try 和 ex ...

  9. 【Python】数值运算操作符

  10. [CF705B] Spider Man - 博弈论

    [CF705B] Description ICG 游戏有若干个环,每次操作将一个环断成非空的两部分,节点数总和不变.集合初态为空,每次向集合中添加一个环,询问当前集合用于游戏的胜负. \(n \le ...