1414: [ZJOI2009]对称的正方形

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 331  Solved: 149
[Submit][Status]

Description

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

Input

文件的第一行为两个整数n和m。接下来n行每行包含m个正整数,表示Orez得到的矩阵。

Output

文件中仅包含一个整数answer,表示矩阵中有answer个上下左右对称的正方形子矩阵。

Sample Input

5 5
4 2 4 4 4
3 1 4 4 3
3 5 3 3 3
3 1 5 3 3
4 2 1 2 4

Sample Output

27

数据范围
对于30%的数据 n,m≤100
对于100%的数据 n,m≤1000 ,矩阵中的数的大小≤109

 
 
  現在我確實是遇到難一點的題套單調隊列就搞不清楚,這道題看了以後很容易想到計算每個點向兩個方向延展的迴文串最長長度,然而如何快速統計卻是個問題,邊長2a的目標正方形滿足其行上連續a的範圍內的格子列方向延展長度大於a,且a小於中心橫向迴文串延展長度。(說的我都暈了),解決這個問題,我用的是單調隊列上二分,單調隊列主要是用來快速解決區間最值問題。
  編的時候出現了三個問題:
  1. manacher算法中忘記更行mx,id變量,導致其退化成O(n^2),在這個問題調試的時候我確信了manacher算法複雜度是嚴格O(n)的。
  2. 單調隊列中兩相鄰元素所夾區間應屬於後面一個元素。
  3. 這樣得題數組大小一定要準確,如果所有下標範圍都開大一倍一定會MLE
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<string>
#include<queue>
using namespace std;
#ifdef WIN32
#define LL "%I64d"
#else
#define LL "%lld"
#endif
#define MAXN 2100
#define MAXV MAXN*2
#define MAXE MAXV*2
#define INF 0x3f3f3f3f
#define INFL 0x3f3f3f3f3f3f3f3fLL
typedef long long qword;
inline int nextInt()
{
char ch;
int x=;
bool flag=false;
do
ch=(char)getchar(),flag=(ch=='-')?true:flag;
while(ch<''||ch>'');
do x=x*+ch-'';
while (ch=(char)getchar(),ch<='' && ch>='');
return x*(flag?-:);
} int n,m;
typedef int arr_t[MAXN];
typedef int arr2[MAXN*];
typedef arr_t map_t[MAXN];
map_t a,b;
map_t sa,sb,tsb,tsa; void manacher(arr2 seq,int n,arr2 &res)
{
int id,mx;
int i,j;
id=mx=-;
int cnt=;
for (i=;i<n;i++)
{
if (i<mx)
{
res[i]=min(mx-i,res[id*-i]);
}else res[i]=;
while (i-res[i]->= && i+res[i]+<n && seq[i+res[i]+]==seq[i-res[i]-])
{
res[i]++;
//cnt++;
}
if (i+res[i]>mx)//Do not forget
{
mx=i+res[i];
id=i;
}
}
return ;
}
void init_p(map_t mp,int n,int m,map_t &sl)
{
int i,j;
arr2 seq,res;
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
seq[j*+]=mp[i][j];
seq[j*]=-INF;
}
seq[*m]=-INF;
manacher(seq,*m+,res);
for (j=;j<m;j++)
{
sl[i][j]=res[j*+];
}
}
}
int pseq[MAXN];
int head,tail;
map_t fa,fb,fc;
void pm(map_t &a)
{
int i,j;
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}
printf("\n");
} void work(map_t &sa,map_t &sb,map_t &fa,int n,int m)
{
int i,j;
for (i=;i<n;i++)
for (j=;j<m/;j++)
{
swap(sb[i][j],sb[i][m-j-]);
swap(sa[i][j],sa[i][m-j-]);
}
for (i=;i<n;i++)
{
head=,tail=;
pseq[]=-;
pseq[]=;
fa[i][m-]=;
for (j=;j<m;j++)
{
while (tail>=head && sb[i][j]<sb[i][pseq[tail]])tail--;
pseq[++tail]=j;
int l,r,mid;
l=-,r=tail;
while (l+<r)
{
int mid=(l+r)>>;
if (sb[i][pseq[mid]]>=j-pseq[mid])
r=mid;
else
l=mid;
}
fa[i][m-j-]=min(j-(pseq[l]+),min(sa[i][j],sb[i][pseq[r]]));
}
}
for (i=;i<n;i++)
for (j=;j<m/;j++)
{
swap(sb[i][j],sb[i][m-j-]);
swap(sa[i][j],sa[i][m-j-]);
} for (i=;i<n;i++)
{
head=,tail=;
pseq[]=-;
pseq[]=;
fa[i][]=;
for (j=;j<m;j++)
{
while (tail>=head && sb[i][j]<sb[i][pseq[tail]])tail--;
pseq[++tail]=j;
int l,r,mid;
l=-,r=tail;
while (l+<r)
{
int mid=(l+r)>>;
if (sb[i][pseq[mid]]>=j-pseq[mid])
r=mid;
else
l=mid;
}
fa[i][j]=min(fa[i][j],min(j-(pseq[l]+),min(sa[i][j],sb[i][pseq[r]])));
}
}
}
int main()
{
//freopen("input.txt","r",stdin);
//freopen("output.txt","w",stdout);
int i,j,k;
int x,y,z;
int ans=;
scanf("%d%d",&n,&m);
memset(a,INF,sizeof(a));
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
scanf("%d",&x);
a[i*+][j*+]=x;
b[j*+][i*+]=x;
}
}
n*=;m*=;n++;m++;
init_p(a,n,m,sa);
init_p(b,m,n,tsb);
for (i=;i<n;i++)
for (j=;j<m;j++)
sb[i][j]=tsb[j][i];
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
sa[i][j]/=;
sb[i][j]/=;
}
} work(sa,sb,fa,n,m); for (i=;i<n;i++)
for (j=;j<m;j++)
tsa[i][j]=a[i][j];
for (i=;i<n;i++)
for (j=;j<m;j++)
b[i][m-j-]=a[m-j-][i]=tsa[i][j];
swap(n,m);
init_p(a,n,m,sa);
init_p(b,m,n,tsb); for (i=;i<n;i++)
for (j=;j<m;j++)
sb[i][j]=tsb[j][i];
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
sa[i][j]/=;
sb[i][j]/=;
}
}
work(sa,sb,fb,n,m);
for (i=;i<n;i++)
for (j=;j<m;j++)
tsb[i][j]=fb[i][j];
swap(n,m);
for (i=;i<n;i++)
for (j=;j<m;j++)
fb[i][j]=tsb[m-j-][i]; //pm(fa);
//pm(fb);
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
fc[i][j]=max(,min(fa[i][j]-(i%==),fb[i][j]-(j%==)));
fc[i][j]=(fc[i][j]+)/;
}
}
//pm(fc);
for (i=;i<n;i++)
{
for (j=;j<m;j++)
{
if (i%+j%==)continue;
ans+=fc[i][j];
}
}
cout<<ans<<endl; }

bzoj 1414: [ZJOI2009]对称的正方形 manacher算法+單調隊列的更多相关文章

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

    Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...

  2. 【bzoj 1414】对称的正方形 单调队列+manacher

    Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们排成了一个n行m列的矩阵.通过观察,Orez发现这些数据蕴涵了一 ...

  3. 【BZOJ1414】[ZJOI2009]对称的正方形(哈希)

    [BZOJ1414][ZJOI2009]对称的正方形(哈希) 题面 BZOJ 洛谷 题解 深思熟虑一波,发现一个矩阵如果左右对称的话,那么它每行都是一个回文串,同理,如果上下对称的话,那么每列都是一个 ...

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

    [BZOJ1414/3705][ZJOI2009]对称的正方形 Description Orez很喜欢搜集一些神秘的数据,并经常把它们排成一个矩阵进行研究.最近,Orez又得到了一些数据,并已经把它们 ...

  5. BZOJ 2342 双倍回文(manacher算法)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=2342 题意:定义双倍回文串为:串的长度为4的倍数且串的前一半.后一半.串本身均是回文的. ...

  6. [luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

    传送门 很蒙蔽,不知道怎么搞. 网上看题解有说可以哈希+二分搞,也有的人说用Manacher搞,Manacher是什么鬼?以后再学. 对于这个题,可以从矩阵4个角hash一遍,然后枚举矩阵中的点,再二 ...

  7. 题解-------[ZJOI2009]对称的正方形

    传送门 题目大意 找到所有的上下左右都相同的正方形. 思路:二分+二维Hash 这道题我们首先想到不能暴力判断一个正方形是否合法. 然后我们发现当一个正方形合法时,以这个正方形为中心且比它小的正方形也 ...

  8. manacher算法学习(求最长回文子串长度)

    Manacher总结 我的代码 学习:yyb luogu题目模板 xzy的模板 #include<iostream> #include<cstdlib> #include< ...

  9. 【学习笔记】Manacher算法

    本文部分图片来源 代码来源(代码是学姐哒.. 一.引入 Manacher算法是用来求最长回文子串的算法,时间复杂度O(n). 回文子串指的是''aacaa'',''noon'',这种正着反着读都一样的 ...

随机推荐

  1. 学习PHP时的一些总结(二)

    类中的构造方法和析构方法: 构造方法是对象创建完成后第一个被对象自动调用的方法.析构方法是对象在销毁之前最后一个被对象自动调用的方法. 如果没有显示的声明构造方法,类中都会默认存在一个没有参数列表并且 ...

  2. java 流程执行 循环 foreach循环

    一. if分支 1. 结构  if  else if   else 2.执行原则 if  if  if 结构  会一直去执行()里的判断语句 if else if  else if 结构  只要一条( ...

  3. Android 自定义View修炼-自定义可动画展开收缩View的实现

    有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...

  4. 2014年最新720多套Android源码2.0GB免费一次性打包下载

    之前发过一个帖子,但是那个帖子有点问题我就重新发一个吧,下面的源码是我从今年3月份开始不断整理源码区和其他网站上的android源码,目前总共有720套左右,根据实现的功能被我分成了100多个类,总共 ...

  5. Google Map API v2 (四)----- 导航路径

    仍然是建议个异步小任务 private GetPathTask mGetPathTask = null; private void getGuidePath(LatLng origin){ if(mG ...

  6. 使用 git 进行项目管理(只管理代码,不管理项目配置)

    使用Git进行项目管理 1. 从服务器pull项目,本地还原工程 从服务器拉取仓库及分支 git clone git@github.com/helloWorld.git git branch -a g ...

  7. Windows PowerShell:管理服务器

    一.概述 Cmdlets 用于服务器的管理方面主要体现在4个方面:服务.日志.进程.服务器管理器. 1.服务 •  Get-Service.查看某个服务的属性. •  New-Service.创建一个 ...

  8. instanceof 含义

    看到一个问题: 把一个字面量对象,变成某个类的实例 function Type() {} var a = {}; ______________ // a instanceof Type === tru ...

  9. 【转】Web前端开发规范文档

    规范目的: 使开发流程更加规范化. 通用规范: TAB键用两个空格代替(WINDOWS下TAB键占四个空格,LINUX下TAB键占八个空格). CSS样式属性或者JAVASCRIPT代码后加“;”方便 ...

  10. xml--小结④DTD的验证问题,不要用IE检验,IE不靠谱

    可以自己写代码 <script type="text/javascript"> var xmldoc = new ActiveXObject("Microso ...