HDU

来源:互联网 发布:python raw input 编辑:程序博客网 时间:2024/06/08 10:07

传送门:点击打开链接

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.
Input
The first line of the input contains an integer T (1 <= T <= 20), which mean there are T test case follow. 
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.
Output
For each test case, output a single integer that is the answer to the problem described above.
Sample Input
1 4 4 abab dacb adab cabb
Sample Output
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;}