3229. 【佛山市选2013】回文子序列

Description

回文序列是指左右对称的序列。例如1 2 3 2 1是回文序列,但是1 2 3 2 2就不是。我们会给定一个N×M的矩阵,你需要从这个矩阵中找出一个P×P的子矩阵,使得这个子矩阵的每一列和每一行都是回文序列。

Input

第一行有两个正整数N, M。

接下来是n行,代表一个N×M的矩阵,矩阵的每个元素都是值不超过31415926的正整数。

Output

输出符合条件的子矩阵的最大大小P。

Sample Input

5 10

1 2 3 3 2 4 5 6 7 8

1 2 3 3 2 4 5 6 7 8

1 2 3 3 2 4 5 6 7 8

1 2 3 3 2 4 5 6 7 8

1 2 3 9 10 4 5 6 7 8

Sample Output

4

Data Constraint

对于20%数据 1 ≤ N, M ≤ 10

对于所有数据 1 ≤ N, M ≤ 300

Solution

据说N^3、N^4、N^5都可以过。

但是我打了一个N^2 log^2 n的方法。

首先将整个矩阵每两个数中间加一个0,对于每行每列做一遍马拉车。

设f[ i ][ j ]表示以第i行第j列为中心的同一行的最长的回文串的长度,g[ i ][ j ]表示同一列的最长回文串的长度。

预处理是N^2的。

然后二分答案。

对于一个点,我们先将同一行的g[][]加入一颗线段树中(或者预处理出RMQ然后用倍增),表示所有的数在列上的最长回文串长度已经知道了,然后判断以当前这个点为中心的回文串的长度是否大于等于mid,再判断以当前点为中心的长度刚好大于等于mid的这一段区间中g[][]的最小值是否大于等于mid,如果是,则mid合法。

因为对于每一列都已经是一个回文串了,如果当前点往左右扩展也是一个回文串的话,那么整个矩阵就都合法了。

注意分开判断回文串长度为奇偶的情况

Code

#include<cstdio> 
#include<cstring>
#include<algorithm>
#include<cmath>
#define I int
#define ll long long
#define ls x<<1
#define rs ls|1
#define F(i,a,b) for(I i=a;i<=b;i++)
#define Fd(i,a,b) for(I i=a;i>=b;i--)
#define N 610 
using namespace std;
I n,m,a[N][N],f[N][N],g[N][N],tr[N<<2],ans=0,k;
void ins(I k,I v,I x=1,I l=1,I r=(m+1)>>1){
	if(l==r){tr[x]=v;return;}
	I M=l+r>>1;
	if(k<=M) ins(k,v,ls,l,M);else ins(k,v,rs,M+1,r);
	tr[x]=min(tr[ls],tr[rs]);
}
I fnd(I l2,I r2,I x=1,I l=1,I r=(m+1)>>1){
	if(r<l2||l>r2) return N;
	if(l>=l2&&r<=r2){return tr[x];}
	I M=l+r>>1;
	return min(fnd(l2,r2,ls,l,M),fnd(l2,r2,rs,M+1,r));
}
I check(I x){
	F(i,1,n){
		memset(tr,0x3f3f,sizeof tr);
		F(j,1,m) if(j&1){ins((j+1)>>1,g[i][j]-1);}
		if(i&1){
			F(j,1,m) if((j&1)&&(f[i][j]-1>=x)){
				if(fnd(((j+1)>>1)-x/2+1,((j+1)>>1)+x/2-1)>=x) return 1;
			}
		}
		else{
			F(j,1,m) if((!(j&1))&&f[i+1][j]-1>=x){
				if(fnd((j>>1)-x/2+1,((j+1)>>1)+x/2-1)>=x) return 1;
			}
		}
	}
	return 0;
}
I main(){
	scanf("%d%d",&n,&m);n=n*2-1,m=m*2-1;I l,r,mid;
	F(i,1,n) if(i&1){
		F(j,1,m) if(j&1) scanf("%d",&a[i][j]);
	}
	F(i,1,n) if(i&1){
		l=r=0;
		F(j,1,m){
			k=(j>r)?1:min(f[i][l+r-j],r-j);
			while(j-k>=0&&j+k<=m+1&&a[i][j-k]==a[i][j+k]) k++;
			f[i][j]=k--;
			if(j+k>r){l=j-k,r=j+k;}
		}
	}
	F(j,1,m) if(j&1){
		l=r=0;
		F(i,1,n){
			k=(i>r)?1:min(g[l+r-i][j],r-i);
			while(i-k>=0&&i+k<=n+1&&a[i-k][j]==a[i+k][j]) k++;
			g[i][j]=k--;
			if(i+k>r){l=i-k,r=i+k;}
		}
	}
	l=0,r=(min(n,m)+1)>>1;
	while(l<=r){
		mid=l+r>>1;
		if(check(mid)) l=(ans=mid)+1;
		else r=mid-1;
	}
	printf("%d\n",ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/107870459