HDU4495-Rectangle
HDU4495-Rectangle
题意
给一个字符矩形(\(n\)*\(m\)),求其中最大的对称的等腰直角三角形的面积(包含的字符个数),其直角边分别平行于矩形的边(对称表示两边字符相等)
题解
总共可能有四种不同的矩形。可以先考虑直角在右下位置的等腰直角三角形,其余可以通过旋转矩形来得到。
令\(dp[i][j]\)表示直角顶点在\((i,j)\)处的最大的三角形的直角边长度,可以得到递推式\(dp[i][j]=min(dp[i-1][j-1]+2,len)\),其中\(len\)表示从点\((i,j)\)分别向上,向左的两个字符串对称的最大长度。
\(len\)可以先预处理,点\((i,j)\)的\(len\)用\(mx[i][j]\)表示,每次二分就可以求出。
注
1、旋转矩形时记得\(swap(n,m)\)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int base=131;
const ll mod=1e9+7;
const int N=510;
int t,n,m;
char s[N][N],tmp[N][N];
ll Hashr[N][N],Hashc[N][N];
ll sum[N];
int mx[N][N],dp[N][N];
int ans;
void getSum(){
sum[0]=1;
for(int i=1;i<=500;i++) sum[i]=(sum[i-1]*base)%mod;
}
void getHash(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
Hashr[i][j]=(Hashr[i][j-1]*base%mod+s[i][j])%mod;
}
}
for(int j=1;j<=m;j++){
for(int i=1;i<=n;i++){
Hashc[i][j]=(Hashc[i-1][j]*base%mod+s[i][j])%mod;
}
}
}
bool check(int i,int j,int len){
int r=j,l=r-len+1;
ll nowr=(Hashr[i][r]-Hashr[i][l-1]*sum[len]%mod+mod)%mod;
r=i;l=r-len+1;
ll nowc=(Hashc[r][j]-Hashc[l-1][j]*sum[len]%mod+mod)%mod;
if(nowr==nowc) return 1;
return 0;
}
void init(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
int l=1,r=min(i,j);
while(l<=r){
int mid=(l+r)>>1;
if(check(i,j,mid)){
mx[i][j]=mid;
l=mid+1;
}else{
r=mid-1;
}
}
}
}
}
void solve(){
getHash();
init();
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
dp[i][j]=min(dp[i-1][j-1]+2,mx[i][j]);
ans=max(ans,dp[i][j]);
}
}
}
//记得swap(n,m)
void rotate(){
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
tmp[j][n-i+1]=s[i][j];
}
}
swap(n,m);
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
s[i][j]=tmp[i][j];
}
}
}
int main(){
scanf("%d",&t);
getSum();
while(t--){
ans=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
solve();
rotate();
solve();
rotate();
solve();
rotate();
solve();
if(ans%2) ans=(ans+1)/2*ans;
else ans=ans/2*(ans+1);
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号