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. ios6如何处理内存,分别为前警告后

    这里有一篇文章.非常具体地说明了ios6前后是怎样处理内存警告的: 来自唐巧的技术博客:http://blog.devtang.com/blog/2013/05/18/goodbye-viewdidu ...

  2. android 74 下载文本

    页面: <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tool ...

  3. linux 安装软件的地方

    用下边这个命令:mysqladmin -u root -p variables root是你的数据库帐号回车后会提示你输入密码,输入上边填写的帐号对应的密码 回车后出来一个大表,找到datadir这一 ...

  4. atlassian-jira-confluence-bitbucket破解

    ==================================================================================================== ...

  5. WTL 自定义 Button类-自绘

    WTL 自绘Button类,支持按钮三种形态,正常模式,hover模式,鼠标按下模式,支持png图片.使用方法很简单: MyButton* pButton = new MyButton;   pBut ...

  6. Unexpected CFBundleExecutable Key

    昨天晚上打包上传的时候报错: ERROR ITMS-90535: "Unexpected CFBundleExecutable Key. The bundle at 'Payload/xxx ...

  7. Xcode4快速Doxygen文档注释 — 简明图文教程

    转自:http://blog.csdn.net/totogo2010/article/details/9100767 准备2个文件: 文件一,ThisService.app 文件二,Doxygen.r ...

  8. homework做了些什么?

    第一步:get_new_guid_uid_pairs_{$ymd} 参数是时间和100上的文件. 那么100上的文件是从哪里来的呢? 我们进入到100机器上,打开root权限下的cron,看到如下内容 ...

  9. php字符串函数(1)

    下面去学习一下php的字符串函数,那么怎么去看手册呢,举个例子 int strcasecmp ( string $str1 , string $str2 ) 第一个int,表示此函数返回的类型是int ...

  10. Java-Junit 的Hello world

    这里介绍junit 4的基本配置: <1>建立一个java project项目. <2>在src目录下面建一个包,com.sun.junit4,在包下面写一点文件T.java ...