HDU - 4495 (字符串哈希+二分+DP)

传送门:点击打开链接

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;
}


字符串哈希滑动窗口是一种用于处理字符串的算法。它主要用于在给定的字符串中找到满足特定条件的子串。 在字符串哈希滑动窗口算法中,我们首先计算原始字符串哈希值。然后,我们使用一个滑动窗口来遍历字符串,每次滑动一个固定长度的窗口。我们可以通过比较每个窗口内的子串的哈希值来判断是否满足条件。 具体而言,我们可以使用BKDRHash等哈希函数来计算字符串哈希值。然后,我们枚举每个可能的起点,并使用滑动窗口来计算窗口内的子串的哈希值。通过比较窗口内的子串的哈希值,我们可以判断是否满足条件。 对于滑动窗口的移动,如果窗口内的子串满足条件,我们可以继续将窗口往右移动一个固定的长度。如果窗口内的子串不满足条件,我们将窗口的右边界移到最右端,并依次比较新窗口内的子串的哈希值。 综上所述,字符串哈希滑动窗口算法是通过计算字符串哈希值,并使用滑动窗口来遍历字符串,以找到满足特定条件的子串。这个算法可以高效地处理字符串,并且能够应用于各种字符串相关的问题。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [String (字符串哈希+滑动窗口)](https://blog.youkuaiyun.com/weixin_43872264/article/details/107571742)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [【字符串hash+滑动窗口】String HDU - 4821](https://blog.youkuaiyun.com/qq_45599865/article/details/111143633)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值