多校第二场——hdu4618——字符串hash,二分

题意:求一个矩阵的最大回文子矩阵。

分奇偶,二分长度,hash判回文。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef unsigned long long lng;

const int maxn = 500;
const int x = 100000007;
int num[maxn][maxn];
lng hash[4][maxn][maxn], xp[maxn];
int n, m;

void prework()
{
    memset(hash, 0, sizeof(hash));
    scanf("%d %d", &n, &m);
    for(int i = 0; i < n; ++i)
        for(int j = 0; j < m; ++j)
            scanf("%d", &num[i][j]);
    for(int i = 0; i < n; ++i)
    {
        hash[0][i][0] = num[i][0];
        for(int j = 1; j < m; ++j)
            hash[0][i][j] = hash[0][i][j - 1] * x + num[i][j];
        hash[1][i][m - 1] = num[i][m - 1];
        for(int j = m - 2; j >= 0; --j)
            hash[1][i][j] = hash[1][i][j + 1] * x + num[i][j];
    }
    for(int i = 0; i < m; ++i)
    {
        hash[2][i][0] = num[0][i];
        for(int j = 1; j < n; ++j)
            hash[2][i][j] = hash[2][i][j - 1] * x + num[j][i];
        hash[3][i][n - 1] = num[n - 1][i];
        for(int j = n - 2; j >= 0; --j)
            hash[3][i][j] = hash[3][i][j + 1] * x + num[j][i];
    }
}

lng gethash(int num, int r, int a, int b)
{
    if(num == 0 || num == 2)
    {
        lng ans = hash[num][r][b];
        if(a > 0) ans -= xp[b - a + 1] * hash[num][r][a - 1];
        return ans;
    }
    else
        return hash[num][r][a] - xp[b - a + 1] * hash[num][r][b + 1];
}

bool check(int len)
{
    bool sign = true;
    for(int i = 0; i + len <= n; ++i)
    {
        for(int j = 0; j + len <= m; ++j)
        {
            for(int k = i; k < i + len; ++k)
            {
                lng h1 = gethash(0, k, j, j + len / 2 - 1);
                lng h2 = gethash(1, k, j + len / 2 + (len % 2), j + len - 1);
                if(h1 != h2) {
                    sign = false;
                    break;
                }
            }
            for(int k = j; k < j + len && sign; ++k)
            {
                lng h1 = gethash(2, k, i, i + len / 2 - 1);
                lng h2 = gethash(3, k, i + len / 2 + (len % 2), i + len - 1);
                if(h1 != h2) {
                    sign = false;
                    break;
                }
            }
            if(sign) return true;
            else sign = true;
        }
    }
    return false;
}


void solve()
{
    int ans = 1;
    if(check(2))
    {
        int l = 1, r = min(n, m);
        if(r % 2) r--;
        r /= 2;
        while(l < r)
        {
            int mid = (l + r) / 2 + 1;
            if(check(2 * mid)) l = mid;
            else r = mid - 1;
        }
        ans = max(2 * l, ans);
    }
    int l = 0, r = min(n, m);
    if(r % 2 == 0) r--;
    r /= 2;
    while(l < r)
    {
        int mid = (l + r) / 2 + 1;
        if(check(2 * mid + 1)) l = mid;
        else r = mid - 1;
    }
    ans = max(ans, 2 * l + 1);
    printf("%d\n", ans);
}


int main()
{
    freopen("in.txt", "r", stdin);
    xp[0] = 1;
    for(int i = 1; i <= 300; ++i) xp[i] = xp[i - 1] * (lng)x;
    int t; cin >> t;
    while(t--)
    {
        prework();
        solve();
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值