1. 程式人生 > >bzoj 1414: [ZJOI2009]對稱的正方形

bzoj 1414: [ZJOI2009]對稱的正方形

zjoi pri 分享 什麽 zjoi2009 urn play mem man

傳送門

我有效率這種東西嗎,那是什麽,可以吃嗎

先對每行每列跑manacher,然後需要求出每個點可以向四周擴展的最大距離,

考慮單獨一行,對於每個i只需求出它前面距它最遠的一個j滿足i-j+1>=min(rad[j]~rad[i])

這個可以用單調隊列維護,維護一個rad值單增的單調隊列,同時記錄隊首最後一個被彈出去的元素的位置,就可以維護了。

那麽對於每行每列都正反跑一遍然後每個點取min,即每個格子對它上下左右預計能擴展的最大正方形邊長取min即可。

需要註意這種整個補了一些奇怪的東西的時候有些格子是沒有貢獻的,計算答案的時候不考慮它。

技術分享圖片
//Achen
#include<algorithm>
#include
<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #include<vector> #include<queue> #include<cmath> #include<ctime> const int N=2007; typedef long long LL; using namespace std; int n,m,a[N][N],mx[N][N],rad1[N][N],rad2[N][N]; template<typename T> void
read(T &x) { T f=1; x=0; char ch=getchar(); while(ch!=-&&(ch<0||ch>9)) ch=getchar(); if(ch==-) f=-1,ch=getchar(); for(;ch>=0&&ch<=9;ch=getchar()) x=x*10+ch-0; x*=f; } int tot,tp[N],rad[N],que[N],ql,qr,last; void work(int id,int f) { tot=(f==1
?m:n); memset(rad,0,sizeof(rad)); for(int i=1;i<=tot;i++) tp[i]=(f==1?a[id][i]:a[i][id]); for(int i=1,j,k=0;i<=tot;) { while(tp[i-k-1]==tp[i+k+1]) k++; rad[i]=k; for(j=1;j<=k&&rad[i-j]!=rad[i]-j;j++) rad[i+j]=min(rad[i-j],rad[i]-j); k=max(k-j,0); i+=j; } for(int i=1;i<=tot;i++) if(f==1) rad1[id][i]=rad[i]; else rad2[i][id]=rad[i]; } void solve(int id,int f) { tot=(f==1?m:n); for(int i=1;i<=tot;i++) if(f==1) rad[i]=rad2[id][i]; else rad[i]=rad1[i][id]; ql=1; qr=0; last=0; for(int i=1;i<=tot;i++) { while(ql<=qr&&rad[que[qr]]>=rad[i]) qr--; que[++qr]=i; while(ql<=qr&&(i-que[ql])+1>rad[que[ql]]) last=que[ql],ql++; int now=0; if(ql<=qr&&(i-que[ql])+1<=rad[que[ql]]) now=min(rad[que[ql]],i-last); if(f==1) mx[id][i]=min(mx[id][i],now); else mx[i][id]=min(mx[i][id],now); } ql=1; qr=0; last=tot+1; for(int i=tot;i>=1;i--) { while(ql<=qr&&rad[que[qr]]>=rad[i]) qr--; que[++qr]=i; while(ql<=qr&&que[ql]-i+1>rad[que[ql]]) last=que[ql],ql++; int now=0; if(ql<=qr&&(que[ql]-i)+1<=rad[que[ql]]) now=min(rad[que[ql]],last-i); if(f==1) mx[id][i]=min(mx[id][i],now); else mx[i][id]=min(mx[i][id],now); } } int main() { #ifdef DEBUG freopen("1.in","r",stdin); freopen("1.out","w",stdout); #endif read(n); read(m); LL ans=n*m; for(int i=1;i<=n;i++) { for(int j=1;j<=2*m+1;j++) a[i*2-1][j]=-1; for(int j=1;j<=m;j++) { a[i*2][j*2-1]=-1; read(a[i*2][j*2]); } a[i*2][m*2+1]=-1; if(i==n) for(int j=1;j<=2*m+1;j++) a[n*2+1][j]=-1; } n=2*n+1; m=2*m+1; memset(mx,127,sizeof(mx)); for(int i=1;i<=n;i++) work(i,1); for(int i=1;i<=m;i++) work(i,-1); for(int i=1;i<=n;i++) solve(i,1); for(int i=1;i<=m;i++) solve(i,-1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(a[i][j]==-1&&(a[i-1][j]!=-1||a[i][j-1]!=-1)) continue; if(a[i][j]!=-1&&mx[i][j]%2==0) mx[i][j]--; else if(a[i][j]==-1&&mx[i][j]&1) mx[i][j]--; if(mx[i][j]/2) ans+=mx[i][j]/2; } printf("%lld\n",ans); return 0; } /* 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 */
View Code

bzoj 1414: [ZJOI2009]對稱的正方形