传送门:点击打开链接
Given a rectangle which contains N rows and each of them contains a string length of M.
You must find out a symmetrical isosceles right triangle (with two equal edges and a right angle) with two edges parallel two side of the rectangle. Symmetry means the value should be the same according to the shortest altitude of the triangle. And just output the area of the triangle.
You must find out a symmetrical isosceles right triangle (with two equal edges and a right angle) with two edges parallel two side of the rectangle. Symmetry means the value should be the same according to the shortest altitude of the triangle. And just output the area of the triangle.
For each test case, the first line contains two integer number N and M (1 <= N, M <= 500) which means described above.
And then N lines follow, which contains a string of length M. The string only contains letters or digits.
1 4 4 abab dacb adab cabb
6题目大意:
给出N*M的矩阵,只包含字母和数字,求最大的对称的等腰三角形的面积(即该对称等腰三角形中字符的个数)
题解:
如:
abdq
bcep
dekh
qphw
可以看出以紫色为对角线的三角形是对称的等腰直角三角形,绿色之间对称,红色之间对称。可见对于一个三角形的
每一层之间(红色为一层,绿色为一层)相差的个数是2。假如已经知道了a[i][j]表示以i,j为直角点的最长等腰的长度,那么dp[i][j] = min(a[i][j],dp[i-1][j-1]+2)表示以i,j为直角点的对称等腰直角三角形的边长。现在怎么求a[i][j]呢?如果直接简单暴力肯定是不行的。现在对每行每列进行哈希,对a[i][j]的长度进行二分求解,因为哈希后在比较时是O(1)的复杂度。如果二分的值相等就说明长度太小,不相等说明二分长度太大。最后因为有四个方向的直角,把矩阵旋转3次求解即可
笔者语言描述能力欠佳,说的比较乱,读者还请谅解。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
typedef unsigned long long LL;
LL seed = 31;
LL f[555];
LL col[555][555],row[555][555];
int a[555][555];
char s[555][555];
int dp[555][555];
LL gethash(int x,int l,int r,int flag){
if(!flag){
return row[x][r]-row[x][l-1]*f[r-l+1];
}
return col[x][r]-col[x][l-1]*f[r-l+1];
}
int work(int n,int m){
memset(a,1,sizeof(a));
int r,l;
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
l = 1;
r = min(n,m);
int ans = 1;
while(l<=r){
int mid = (l+r)>>1;
if(mid>(m-j+1)||mid>(n-i+1)){
r = mid-1;
continue;
}
LL q = gethash(i,j,mid+j-1,0);
LL p = gethash(j,i,mid+i-1,1);
if(q==p){
ans = mid;
l = mid+1;
}
else r =mid-1;
}
a[i][j] = ans;
}
}
int mx = 1;
memset(dp,0,sizeof(dp));
for(int i = n;i>=1;i--){
for(int j = m;j>=1;j--){
dp[i][j] = min(a[i][j],dp[i+1][j+1]+2);
mx=max(mx,dp[i][j]);
}
}
return mx;
}
void init(int n,int m){
memset(row,0,sizeof(row));
for(int i = 1;i<=n;i++){
for(int j = 1;j<=m;j++){
row[i][j] = row[i][j-1]*seed+s[i][j];
}
}
memset(col,0,sizeof(col));
for(int i = 1;i<=m;i++){
for(int j = 1;j<=n;j++){
col[i][j] = col[i][j-1]*seed+s[j][i];
}
}
}
char temp[555][555];
void turn(int n,int m){
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
temp[j][n-i+1] = s[i][j];
for(int i = 1; i <= m; i++)
for(int j = 1; j <= n; j++)
s[i][j] = temp[i][j];
}
int main(){
int T ;
f[0]=1;
for(int i = 1;i<=505;i++){
f[i] = f[i-1]*seed;
}
scanf("%d",&T);
while(T--){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 1;i<=n;i++){
scanf("%s",s[i]+1);
}
int mx = 1;
init(n,m);
mx = max(mx,work(n,m));
turn(n,m);
swap(n,m);
init(n,m);
mx = max(mx,work(n,m));
turn(n,m);
swap(n,m);
init(n,m);
mx = max(mx,work(n,m));
turn(n,m);
swap(n,m);
init(n,m);
mx = max(mx,work(n,m));
printf("%d\n",mx*(mx+1)/2);
}
return 0;
}