HDU 4618 Palindrome Sub-Array(Manacher、二分)
来源:互联网 发布:ifile是什么软件 编辑:程序博客网 时间:2024/06/06 00:57
题意:
给定N×M,N,M≤300的矩阵,求最大的回文正方形的边长
分析:
现场过了120,我真是一口老血,明明挺难的一个题
赛后尼玛一看,卧槽O(n5)的算法过了,n2枚举点,n枚举边长,n2判断回文
赛上想对了,可是写法很绕,绕了我很久,尼玛Manacher倍增真吃空间,hdu真抠还卡空间
我想的这个正解真的是很麻烦,−−本来没想完,被队友提示二分就会了
p1[i][j]:=i行的以j为中心的回文半径,p2[i][j]:=i列的以j为中心的回文半径
−−被卡了空间,我重复利用了一下这个数组
至于求法,就每行来一遍Manacher,然后再每列来一遍(相当于把矩阵转置之后每行来一遍)
然后绕人的开始了−−,来看题目答案的这个正方形,插入了#是这个样的
1234567891 #########2 #2#3#3#2#3 #########4 #2#3#3#2#5 #########6 #2#3#3#2#7 #########8 #2#3#3#2#9 #########
我们已经知道第5行每个#的 纵向的回文半径长度,以及第5列每个#的 横向的回文半径长度
显然通过行我们可以知道列回文长度(最小的那个),通过列我们可以知道行回文长度(最小的那个)
如何快速查询呢,−−显然区间RMQ,行列分别维护300∗2个SparseTable就好了
显然这个判断回文正方形的复杂度是O(logn)的
蓝儿我们要枚举点,枚举长度,然后在对应的2个st里查询RMQ,判断是否合法,这样复杂度是O(n3logn)
这样会T,不是我想要的,赛上我想到了这里,然后队友冷不丁冒出个二分
我说这没有单调性啊,然后立马想到奇偶分开。。。
卧槽,枚举左上角点,奇偶长度二分,然后复杂度瞬间就O(n2log2n)了,然后就可以AC了
其实之前还想到哈希判断的,但是我让他们写他们不写,因为子串太多,哈希碰撞会哭,蓝儿有这么过的
数据弱要寄刀片啊
代码:
//// Created by TaoSama on 2016-02-25// Copyright (c) 2016 TaoSama. All rights reserved.//#pragma comment(linker, "/STACK:1024000000,1024000000")#include <algorithm>#include <cctype>#include <cmath>#include <cstdio>#include <cstdlib>#include <cstring>#include <iomanip>#include <iostream>#include <map>#include <queue>#include <string>#include <set>#include <vector>using namespace std;#define pr(x) cout << #x << " = " << x << " "#define prln(x) cout << #x << " = " << x << endlconst int N = 3e2 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7;int n, m, a[N][N], b[N][N];int s[N << 1], p[N][N << 1];void manacher(int *a, int *p, int n) { s[0] = '@'; s[1] = '#'; int l = 2; for(int i = 1; i <= n; ++i) { s[l++] = a[i]; s[l++] = '#'; } s[l] = 0; int mx = 0, id; for(int i = 1; i < l; ++i) { if(mx > i) p[i] = min(mx - i, p[2 * id - i]); else p[i] = 1; while(s[i - p[i]] == s[i + p[i]]) ++p[i]; if(mx < p[i] + i) mx = p[i] + i, id = i; }}struct SparseTable { int n, dp[10][N << 1]; void init(int _n) { n = _n; for(int i = 1; (1 << i) <= n; ++i) for(int j = 1; j + (1 << i) - 1 <= n; ++j) dp[i][j] = min(dp[i - 1][j], dp[i - 1][j + (1 << i - 1)]); } int RMQ(int l, int r) { int k = 31 - __builtin_clz(r - l + 1); return min(dp[k][l], dp[k][r - (1 << k) + 1]); }} hor[N << 1], ver[N << 1];bool check(int x) { int ret = 0; for(int i = 1; i <= 2 * n + 1; i += 2) { for(int j = 1; j <= 2 * m + 1; j += 2) { int right = j + 2 * x, down = i + 2 * x; if(right > 2 * m + 1 || down > 2 * n + 1) continue; int h = hor[i + x].RMQ(j, right), v = ver[j + x].RMQ(i, down); int cur = min(h, v); if(cur - 1 >= x) { return true; } } } return false;}int main() {#ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin);// freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout);#endif ios_base::sync_with_stdio(0); int t; scanf("%d", &t); while(t--) { scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++i) for(int j = 1; j <= m; ++j) scanf("%d", &a[i][j]), b[j][i] = a[i][j]; //rows for(int i = 1; i <= n; ++i) manacher(a[i], p[i], m); for(int i = 1; i <= 2 * m + 1; ++i) { for(int j = 1; j <= 2 * n + 1; ++j) { int tmp = INF; if(!(j & 1)) tmp = p[j / 2][i]; ver[i].dp[0][j] = tmp; } ver[i].init(2 * n + 1); } //columns for(int i = 1; i <= m; ++i) manacher(b[i], p[i], n); for(int i = 1; i <= 2 * n + 1; ++i) { for(int j = 1; j <= 2 * m + 1; ++j) { int tmp = INF; if(!(j & 1)) tmp = p[j / 2][i]; hor[i].dp[0][j] = tmp; } hor[i].init(2 * m + 1); } int ans = 0; { int l = 0, r = 150; while(l <= r) { int m = l + r >> 1; if(check(2 * m)) l = m + 1; else r = m - 1; } --l; ans = max(ans, 2 * l); } { int l = 0, r = 150; while(l <= r) { int m = l + r >> 1; if(check(2 * m + 1)) l = m + 1; else r = m - 1; } --l; ans = max(ans, 2 * l + 1); } printf("%d\n", ans); } return 0;}
- HDU 4618 Palindrome Sub-Array(Manacher、二分)
- hdu 4618 Palindrome Sub-Array(dp)
- Hdu 4618 Palindrome Sub-Array
- hdu 4618 Palindrome Sub-Array
- HDU 4618 Palindrome Sub-Array
- Hdu 4618 Palindrome Sub-Array
- HDU-4618-Palindrome Sub-Array
- hdu 4618 Palindrome Sub-Array
- HDU 4618 Palindrome Sub-Array
- HDU 4618 Palindrome Sub-Array 解题报告
- hdu 4618——Palindrome Sub-Array
- HDU 4618 Palindrome Sub-Array (HASH + 枚举)
- HDU 4618 Palindrome Sub-Array 二分(奇偶)+hash判断是否对称
- 2013 多校第二场 hdu 4618 Palindrome Sub-Array
- hdu 4618 Palindrome Sub-Array 多校第二场
- HDU 4618 Palindrome Sub-Array(最大回文子矩阵)
- HDU 4618Palindrome Sub-Array(暴力枚举每一个正方形)
- 多校训练 1008 Palindrome Sub-Array----------manacher算法
- 安卓 播放MP3 实现歌词同步例子
- 支付宝接口
- 反射(Reflection)
- 如何实现动态规划?——TWO
- ubuntu---从网页上下载文件到当前目录 和 从本地上传文件到当前目录
- HDU 4618 Palindrome Sub-Array(Manacher、二分)
- HDU 4619 Warm up 2(贪心、并查集 | 二分图最大独立集)
- Java学习源代码学习(总一天我能够学习源码!)
- Java学习源代码学习
- HDU 4620 Fruit Ninja Extreme(搜索)
- ncurses笔记(1)——ncurses库的介绍与安装
- CentOS6.5安装mysql5.7.11
- LeetCode Add Digits
- codeblocks 搭建opencv