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

Posted Achen

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 1414: [ZJOI2009]对称的正方形相关的知识,希望对你有一定的参考价值。

传送门

我有效率这种东西吗,那是什么,可以吃吗

先对每行每列跑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]对称的正方形的主要内容,如果未能解决你的问题,请参考以下文章

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

BZOJ1433: [ZJOI2009]假期的宿舍

bzoj1433: [ZJOI2009]假期的宿舍

BZOJ 1432: [ZJOI2009]Function

bzoj 1414对称的正方形 单调队列+manacher

bzoj 1433: [ZJOI2009]假期的宿舍