[BZOJ1414][ZJOI2009]对称的正方形(manacher+单调栈+二分)
来源:互联网 发布:mac子弹头口红价格 编辑:程序博客网 时间:2024/06/11 03:09
题目描述
传送门
题解
跟这道题gang了半晚上,写出来了一个理论复杂度
网上题解貌似是二分+hash?好像也有用manacher+单调队列并且时间复杂度科学的方法,不过各种看不懂…
首先我们参考manacher的做法,将一些分隔符插入矩阵,来处理奇数偶数
并且对于每一个点都求出来它横纵的最长回文子串
然后枚举对称中心,二分这个对称中心能得到的最大矩形边长
而如果这样二分的话,需要查询二分到的区间横纵回文子串的最小值来判断
如果这题内存够的话,可以用st表实现
可关键是这题内存不够…
那么我们没法预处理st表,但是同样需要查询一段区间的最小值,怎么办呢?
查询区间最值要考虑用单调队列或单调栈,关键是寻找单调性
刚开始我觉得这道题是毫无单调性的,因为每一个点的最长回文子串根本没有规律
但是我们可以考虑把四个方向拆开,也就是说,每一次只处理某一个方向上的最长回文子串的一半
可以发现如果这样处理的话,满足单调性的主要有两个:
①回文中心单调插入②同一个回文中心答案单调
在插入回文中心的时候,维护一个自底向上单调递增的栈,记录栈中每一个元素的位置
还有一个重要的单调性:栈中元素的位置和权值都是单调的
同样是二分一个回文中心的答案,然后每一次在栈中二分第一个小于等于(或大于等于)它的数,即为最小值
这样上下左右做4遍,4个方向的答案取min即为以这个点为中心的正方形的边长
注意特判一些不合法的情况…注意剪枝…
代码
#include<algorithm>#include<iostream>#include<cstring>#include<cstdio>#include<cmath>using namespace std;#define N 2005#define inf 1000000000int n,m,cn,cm,id,mx,ans;int a[N][N],s[N][N],p[N][N],q[N][N];int top,stack[N],est[N][N];int findll(int loc){ int l=1,r=top,mid,ans; while (l<=r) { mid=(l+r)>>1; if (stack[mid]>=loc) ans=mid,r=mid-1; else l=mid+1; } return stack[ans];}int findrr(int loc){ int l=1,r=top,mid,ans; while (l<=r) { mid=(l+r)>>1; if (stack[mid]<=loc) ans=mid,r=mid-1; else l=mid+1; } return stack[ans];}int findlp(int x,int y){ int l=3,r=p[x][y],mid,ans=0,loc,Min; while (l<=r) { mid=(l+r)>>1; loc=y-mid+1;Min=findll(loc); if (q[x][Min]>=mid) ans=mid,l=mid+1; else r=mid-1; } return ans;}int findrp(int x,int y){ int l=3,r=p[x][y],mid,ans=0,loc,Min; while (l<=r) { mid=(l+r)>>1; loc=y+mid-1;Min=findrr(loc); if (q[x][Min]>=mid) ans=mid,l=mid+1; else r=mid-1; } return ans;}int findlq(int x,int y){ int l=3,r=q[x][y],mid,ans=0,loc,Min; while (l<=r) { mid=(l+r)>>1; loc=x-mid+1;Min=findll(loc); if (p[Min][y]>=mid) ans=mid,l=mid+1; else r=mid-1; } return ans;}int findrq(int x,int y){ int l=3,r=q[x][y],mid,ans=0,loc,Min; while (l<=r) { mid=(l+r)>>1; loc=x+mid-1;Min=findrr(loc); if (p[Min][y]>=mid) ans=mid,l=mid+1; else r=mid-1; } return ans;}int main(){ scanf("%d%d",&n,&m);ans=n*m; for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) scanf("%d",&a[i][j]); for (int i=0;i<=(m<<1|1);++i) s[0][i]=inf+1; for (int i=0;i<=(n<<1|1);++i) s[i][0]=inf+1; cn=0; for (int i=1;i<=n;++i) { ++cn; for (int j=1;j<=(m<<1|1);++j) s[cn][j]=inf+2; ++cn;cm=0; for (int j=1;j<=m;++j) s[cn][++cm]=inf+2,s[cn][++cm]=a[i][j]; s[cn][++cm]=inf+2; } ++cn; for (int j=1;j<=(m<<1|1);++j) s[cn][j]=inf+2; n=n<<1|1,m=m<<1|1; for (int i=1;i<=n;++i) { id=mx=0; for (int j=1;j<=m;++j) { if (j<mx) p[i][j]=min(p[i][2*id-j],mx-j); else p[i][j]=1; while (s[i][j-p[i][j]]==s[i][j+p[i][j]]) ++p[i][j]; if (j+p[i][j]>mx) { mx=j+p[i][j]; id=j; } } } for (int i=1;i<=m;++i) { id=mx=0; for (int j=1;j<=n;++j) { if (j<mx) q[j][i]=min(q[2*id-j][i],mx-j); else q[j][i]=1; while (s[j-q[j][i]][i]==s[j+q[j][i]][i]) ++q[j][i]; if (j+q[j][i]>mx) { mx=j+q[j][i]; id=j; } } } memset(est,127,sizeof(est)); for (int i=1;i<=n;++i) { top=0; for (int j=1;j<=m;++j) { while (top&&q[i][j]<=q[i][stack[top]]) --top; stack[++top]=j; if ((i&1)!=0&&(j&1)==0||(i&1)==0&&(j&1)!=0||est[i][j]<=2) continue; est[i][j]=min(est[i][j],findlp(i,j)); } top=0; for (int j=m;j>=1;--j) { while (top&&q[i][j]<=q[i][stack[top]]) --top; stack[++top]=j; if ((i&1)!=0&&(j&1)==0||(i&1)==0&&(j&1)!=0||est[i][j]<=2) continue; est[i][j]=min(est[i][j],findrp(i,j)); } } for (int i=1;i<=m;++i) { top=0; for (int j=1;j<=n;++j) { while (top&&p[j][i]<=p[stack[top]][i]) --top; stack[++top]=j; if ((j&1)!=0&&(i&1)==0||(j&1)==0&&(i&1)!=0||est[j][i]<=2) continue; est[j][i]=min(est[j][i],findlq(j,i)); } top=0; for (int j=n;j>=1;--j) { while (top&&q[j][i]<=q[stack[top]][i]) --top; stack[++top]=j; if ((i&1)!=0&&(j&1)==0||(i&1)==0&&(j&1)!=0||est[j][i]<=2) continue; est[j][i]=min(est[j][i],findrq(j,i)); if (est[j][i]-1>1) ans+=(est[j][i]-1)/2; } } printf("%d\n",ans);}
0 0
- [BZOJ1414][ZJOI2009]对称的正方形(manacher+单调栈+二分)
- bzoj1414: [ZJOI2009]对称的正方形
- bzoj1414 [ZJOI2009]对称的正方形 && bzoj3705 对称的正方形
- [ZJOI2009对称的正方形]ST+Manacher
- 1414: [ZJOI2009]对称的正方形 Hash+二分
- BZOJ 1414 ZJOI2009 对称的正方形 Hash+二分
- [BZOJ]1414: [ZJOI2009]对称的正方形 二分+hash
- bzoj 1414: [ZJOI2009]对称的正方形
- bzoj 1414: [ZJOI2009]对称的正方形
- NKOJ 2663 (ZJOI 2009)对称的正方形(Manacher)
- ZJOI 2009 对称的正方形 ST+Manacher
- ZJOI 2009 对称的正方形 RMQ+Manacher
- bzoj 1414 && bzoj 3705: [ZJOI2009]对称的正方形(二维Hash)
- bzoj 1414 对称的正方形
- 洛谷2055 [ZJOI2009]假期的宿舍(二分图)
- 二分图匹配匈牙利算法([ZJOI2009]假期的宿舍)
- bzoj1433: [ZJOI2009]假期的宿舍(二分图匹配)
- 单调栈1004 scu2801 正方形
- POJ - 1185 炮兵阵地
- [Leetcode] Remove Duplicates from Sorted List II
- LeetCode-476. Number Complement-思路详解-C++
- 共享动画的实现(AndroidL及以上)
- 设计模式之外观模式
- [BZOJ1414][ZJOI2009]对称的正方形(manacher+单调栈+二分)
- Java多态
- profile=epp.package.java, phase=org.eclipse.equinox.internal.p2.engine.phases.Collect, operand=, act
- 常用的字符串函数
- 设计模式【2】-对象行为型-状态模式
- jquery 鼠标经过行变色
- 精妙Sql语句
- Openstack学习(一)---------------网络服务Neutron
- iOS开发之第三方支付支付宝支付教程,史上最新最全第三方支付宝支付方式实现、支付宝集成教程,支付宝实现流程