1. 程式人生 > >【bzoj 1414】對稱的正方形 單調隊列+manacher

【bzoj 1414】對稱的正方形 單調隊列+manacher

include 正方形 div using getchar() i++ swe mar 簡單的

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 }

【bzoj 1414】對稱的正方形 單調隊列+manacher