zoukankan      html  css  js  c++  java
  • 【bzoj 1414】对称的正方形 单调队列+manacher

    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

    题解:

      蒟蒻写了4h……(本来是想怂,但看到人家说gang了一晚上,然后默默关了网页自己去作了),还有,膜bzoj 1414榜上900B+400MS大佬。

       首先用manacher,双倍复制原数组,跑出$P_{0,i,j},P_{1,i,j}$,分别表示第i行j列的横着的和竖着的回文半径。

      显然只要求出每个位置的最大正方形边长答案就出来了。

      我们以每个位置$(i,j)$为坐标轴原点,显然,我们只要得到x,y轴上的回文半径即可。先讨论x非负轴。同时,对于每个位置我们可以观察发现,在x轴上的位置,应该满足其$x-p[1][i][x]+1<=j$。然后发现对于$(i,j+1)$是可以继承满足$(i,j)$的一部分点,而不能继承的只有$(i,j)$在x轴对应点,同时我们可能会有一部分新点加入$(i,j+1)$的集合点。(⊙v⊙)嗯,这不就是队列的时间关系嘛。

      然后怎么选取$(i,j)$所能得到的此时尽可能最大值边长呢。我们可以画个图,观察发现,我们在$(i,j)$点集的选取,只和最小值有关,所以当出现第一个不满足$x-p_{1,i,x}+1<=j$的点就没必要再在非负半轴上往后扫了。

      证明的话倒是挺简单的,就不多说了。

      以上一结合就得到了我们需要的数据结构,单调队列。

      那么对于x非正半轴以及y轴的情况也与x非负半轴的情况相同。时间复杂度$O(n^{2})$

      最后答案累加每个$(i,j)$奇偶性相同的位置即可。

    Ps:可能是我打得蠢……都跑不过带$log$的……

    代码:

      

      1 #include<cstdio>
      2 #include<iostream>
      3 #include<cstring>
      4 using namespace std;
      5 inline int read(){
      6     int s=0;char ch=getchar();
      7     while(ch<'0'||ch>'9')   ch=getchar();
      8     while(ch>='0'&&ch<='9') s=s*10+(ch^48),ch=getchar();
      9     return s;
     10 }
     11 int n,m;
     12 int Mar[2010][2010];
     13 int p[2][2010][2010];
     14 inline void manacher(){
     15     for(int i=1;i<=2*n+1;i++){
     16         int pos,mar=0;
     17         for(int j=1;j<=2*m+1;j++){
     18             if(mar>j)   p[0][i][j]=min(p[0][i][pos*2-j],mar-j-1);
     19             else    p[0][i][j]=1;
     20             while(Mar[i][j-p[0][i][j]]==Mar[i][j+p[0][i][j]])   p[0][i][j]++;
     21             if(mar<j+p[0][i][j]-1)
     22                 mar=j+p[0][i][j]-1,pos=j;
     23         }
     24     }
     25     for(int i=1;i<=2*m+1;i++){
     26         int pos,mar=0;
     27         for(int j=1;j<=2*n+1;j++){
     28             if(mar>j)   p[1][i][j]=min(p[1][i][pos*2-j],mar-j-1);
     29             else    p[1][i][j]=1;
     30             while(Mar[j-p[1][i][j]][i]==Mar[j+p[1][i][j]][i])   p[1][i][j]++;
     31             if(mar<j+p[1][i][j]-1)
     32                 mar=j+p[1][i][j]-1,pos=j;
     33         }
     34     }
     35 }
     36 int que[2010],l,r;
     37 int re[2010][2010];
     38 int main(){
     39     n=read(),m=read();
     40     for(int i=1;i<=n;i++)
     41         for(int j=1;j<=m;j++)
     42             Mar[i<<1][j<<1]=read();
     43     for(int i=1;i<=2*n+1;i++)
     44         Mar[i][0]=-2,Mar[i][m+1<<1]=-1;
     45     for(int i=1;i<=2*m+1;i++)
     46         Mar[0][i]=-2,Mar[n+1<<1][i]=-1;
     47     manacher();
     48     for(int i=2;i<=2*n;i++){
     49         l=1,r=0;
     50         for(int j=((i^1)&1)+1,k=1;j<=2*m+1;j+=2){
     51             while(k<=2*m+1&&k-p[1][k][i]+1<=j){
     52                 while(l<=r&&p[1][que[r]][i]>=p[1][k][i])
     53                     r--;
     54                 que[++r]=k;
     55                 k++;
     56             }
     57             while(l<=r&&que[l]<j)
     58                 l++;
     59             re[i][j]=min(que[r]-j+1,p[1][que[l]][i]); 
     60         }
     61         l=1,r=0;
     62         for(int j=2*m+1-((i^1)&1),k=2*m+1;j>=0;j-=2){
     63             while(k&&k+p[1][k][i]-1>=j){
     64                 while(l<=r&&p[1][que[r]][i]>=p[1][k][i])
     65                     r--;
     66                 que[++r]=k--;
     67             }
     68             while(l<=r&&que[l]>j)
     69                 l++;
     70             re[i][j]=min(min(j-que[r]+1,p[1][que[l]][i]),re[i][j]);
     71         }
     72         
     73     }
     74     for(int i=2;i<=2*m;i++){
     75         l=1,r=0;
     76         for(int j=1+((i^1)&1),k=1;j<=2*n+1;j+=2){
     77             while(k<=2*n+1&&k-p[0][k][i]+1<=j){
     78                 while(l<=r&&p[0][que[r]][i]>=p[0][k][i])
     79                     r--;
     80                 que[++r]=k;
     81                 k++;
     82             }
     83             while(l<=r&&que[l]<j)
     84                 l++;
     85             re[j][i]=min(min(que[r]-j+1,p[0][que[l]][i]),re[j][i]); 
     86         }
     87         l=1,r=0;
     88         for(int j=2*n+1-((i^1)&1),k=2*n+1;j;j--){
     89             while(k&&k+p[0][k][i]-1>=j){
     90                 while(l<=r&&p[0][que[r]][i]>=p[0][k][i])
     91                     r--;
     92                 que[++r]=k--;
     93             }
     94             while(l<=r&&que[l]>j)
     95                 l++;
     96             re[j][i]=min(min(j-que[r]+1,p[0][que[l]][i]),re[j][i]);
     97         }
     98     }
     99     int ans=0;
    100     for(int i=2;i<=2*n;i++){
    101         for(int j=((i^1)&1)+1;j<=2*m+1;j+=2)
    102             if((i&1)==(j&1))
    103                 ans+=re[i][j]>>1;
    104     }
    105     printf("%d",ans);
    106 }
  • 相关阅读:
    SET/JFace ProgressIndicator的使用以及来回滚动进度条实际使用示例
    Java/SWT/JFace项目打包总结注意事项
    StyledText实现的简单Java类文件编辑器
    命令行界面的简单银行系统
    TC二次开发遇到的问题总结
    用Java模仿简单的Ping命令
    Oracle SQL Developer定制每天执行一次存储过程的计划任务
    关于SpringMVC中text/plain的编码导致的乱码问题解决方法
    Spring框架下的定时任务quartz框架的使用
    Delphi 函数参数修饰中的var 、out和const
  • 原文地址:https://www.cnblogs.com/Troywar/p/7535112.html
Copyright © 2011-2022 走看看