HDU 4618 Palindrome Sub-Array 解题报告

来源:互联网 发布:数据交叉分析 编辑:程序博客网 时间:2024/09/21 09:28

题目

2013 多校第二场 总结

题意:

有一个全由数字组成的矩阵,你要找到一个最大的子正方形,且这个正方形每一行每一列都是回文串。

解法一:

先假设正方形的边长len为奇数,那么对于中心点(x,y),所有的(x-len/2,y)~(x+len/2,y)(y同理)都要是至少回文半径为len/2+1的回文串。如果我们事先用manacher求出所有的行和列的回文半径的话,用rmq就知道(x-len/2,y)~(x+len/2,y)是否满足要求。据说不用rmq直接一个个验证更快。

len是偶数咋办?像manacher一样,填充原矩阵,就不用管奇偶的问题了,但是中心点所在的行列要么都是填充的,要么都不是填充的。


//Time:296ms
//Memory:17960KB//Length:2940B#include <iostream>#include <cstdio>#include <cstdlib>#include <cstring>#include <cmath>#define MAXN 620#define INF 1007using namespace std;int arr[MAXN][MAXN],tarr[MAXN];short rad[2][MAXN][MAXN];short rmq[2][MAXN][MAXN][10];int ilog[MAXN];void manacher(int a[],short r[],int len){    for(int i=0;i<len;++i)  r[i]=0;    r[0]=1;    for(int i=1,j=0,k;i<len;)    {        while(a[i-j-1]==a[i+j+1])   ++j;        r[i]=j;        for(k=1;k<=j&&r[i-k]!=r[i]-k;++k)            r[i+k]=min((int)r[i-k],r[i]-k);        i+=k;        j=max(0,j-k);    }}void calrmq(int a[],short r[][10],int len){    int fe=log(len)/log(2)+1;    for(int i=0;i<len;++i)  r[i][0]=a[i];    for(int i=1,j=1;i<fe;++i,j*=2)        for(int k=0;k<len;++k)            if(k+j<len)                r[k][i]=min(r[k][i-1],r[k+j][i-1]);            else    r[k][i]=r[k][i-1];}bool check(int x,int y,int len){    int fe=ilog[len*2],ji;    short tlen=INF;    ji=1<<fe;    tlen=min(tlen,min(rmq[0][y][x-len][fe],rmq[0][y][x+len-ji+1][fe]));    tlen=min(tlen,min(rmq[1][x][y-len][fe],rmq[1][x][y+len-ji+1][fe]));    return tlen>=len;}int main(){    //freopen("/home/moor/Code/input","r",stdin);    int ncase,n,m,ans,nn,mm,tmp;    scanf("%d",&ncase);    for(int i=1;i<MAXN;++i)        ilog[i]=log(i*1.0)/log(2.0);    while(ncase--)    {        ans=0;        scanf("%d%d",&n,&m);        nn=n*2+3,mm=m*2+3;        memset(arr,-1,sizeof(arr));        for(int i=0;i<n;++i)            for(int j=0;j<m;++j)                scanf("%d",&arr[(i+1)*2][(j+1)*2]);        n=n*2+3,m=m*2+3;        for(int i=0;i<m;++i)            arr[0][i]=-2,arr[n-1][i]=-3;        for(int i=0;i<n;++i)            arr[i][0]=-4,arr[i][m-1]=-5;        arr[0][0]=-10,arr[n-1][0]=-11,arr[0][m-1]=-12,arr[n-1][m-1]=-13;        for(int i=0;i<n;++i)            manacher(arr[i],rad[0][i],m);        for(int i=0;i<m;++i)        {            for(int j=0;j<n;++j)    tarr[j]=arr[j][i];            manacher(tarr,rad[1][i],n);        }        for(int i=0;i<m;++i)        {            for(int j=0;j<n;++j)    tarr[j]=rad[0][j][i];            calrmq(tarr,rmq[0][i],n-1);        }        for(int i=0;i<n;++i)        {            for(int j=0;j<m;++j)    tarr[j]=rad[1][j][i];            calrmq(tarr,rmq[1][i],m-1);        }        for(int i=1;i<n;++i)            for(int j=1;j<m;++j)            {                if((j%2==1)&&(i%2==0)||(j%2==0)&&(i%2==1))  continue;                int l=1,r=min(min(i-1,n-i),min(j-1,m-j)),mid;                while(l<r)                {                    if(ans>=r)   break;                    mid=(l+r+1)/2;                    if(check(i,j,mid))     l=mid;                    else    r=mid-1;                }                ans=max(ans,l);            }        printf("%d\n",ans);    }    return 0;}

解法二:

二分(奇偶)+hash判断是否对称,其实好暴力的,但是竟然比上面的快,比赛没敢敲==

代码:

//time:     109ms//length:   2299B//memory:   3504K#include <cstdio>#include <cstdlib>#include <cstring>#include <algorithm>using namespace std;#define maxn 305int n,m,a[maxn][maxn];long long int p[maxn],hash_r[2][maxn][maxn],hash_c[2][maxn][maxn];void hash(){    for (int i=1;i<=n;i++)    {        for (int j=1;j<=m;j++)            hash_r[0][i][j]=hash_r[0][i][j-1]*131+a[i][j];        for (int j=m;j>=1;j--)            hash_r[1][i][j]=hash_r[1][i][j+1]*131+a[i][j];    }    for (int i=1;i<=m;i++)    {        for (int j=1;j<=n;j++)            hash_c[0][j][i]=hash_c[0][j-1][i]*131+a[j][i];        for (int j=n;j>=1;j--)            hash_c[1][j][i]=hash_c[1][j+1][i]*131+a[j][i];    }}long long int calr0(int r,int x,int y) {return hash_r[0][r][y]-hash_r[0][r][x-1]*p[y-x+1];}long long int calr1(int r,int x,int y) {return hash_r[1][r][x]-hash_r[1][r][y+1]*p[y-x+1];}long long int calc0(int c,int x,int y) {return hash_c[0][y][c]-hash_c[0][x-1][c]*p[y-x+1];}long long int calc1(int c,int x,int y) {return hash_c[1][x][c]-hash_c[1][y+1][c]*p[y-x+1];}bool check(int l){    for (int i=1;i+l-1<=n;i++)        for (int j=1;j+l-1<=m;j++)        {            bool flag=true;            for (int k=i;k<=i+l-1&&flag;k++)                if (calr0(k,j,j+l/2-1)!=calr1(k,j+l/2+l%2,j+l-1))                    flag=false;            for (int k=j;k<=j+l-1&&flag;k++)                if (calc0(k,i,i+l/2-1)!=calc1(k,i+l/2+l%2,i+l-1)) flag=false;            if (flag) return true;        }    return false;}int main(){    //freopen("/home/christinass/code/in.txt","r",stdin);    p[0]=1;    for (int i=1;i<=300;i++) p[i]=p[i-1]*131;    int cas;    scanf("%d",&cas);    while (cas--)    {        scanf("%d%d",&n,&m);        for (int i=1;i<=n;i++)            for (int j=1;j<=m;j++)                scanf("%d",&a[i][j]);        hash();        int l=0,r=n/2,ans=1;        while (l<=r)        {            int mid=(l+r)>>1;            if (check(2*mid+1)) ans=2*mid+1,l=mid+1;            else r=mid-1;        }        l=(ans+1)/2,r=n/2;        while (l<=r)        {            int mid=(l+r)>>1;            if (check(2*mid)) ans=2*mid,l=mid+1;            else r=mid-1;        }        printf("%d\n",ans);    }    return 0;}


原创粉丝点击