URAL 1486 Equal Squares 二维Hash

Hash在信息学竞赛中的一类应用 论文中的第一道例题,关于二维hash的一些处理方法和小技巧
  • 通过RK法计算hash值如果不取模的话可以O(n)预处理,然后O(1)得到任意一个字串的hash值
  • 得到任意子串的hash值的时候不能用除和取模运算了,显然是错的
  • 二维hash如果使用RK法每一次的p值必须不一样
  • 如果不能确定hash值一定不是唯一的,可以计算一个用来确定pos 的hash值和一个用来确定值的hash值

代码写的相当挫,不忍直视

#include <cstdio>
#include <cstring>
#include <iostream>
#include <map>
#include <set>
#include <vector>
#include <string>
#include <queue>
#include <deque>
#include <bitset>
#include <list>
#include <cstdlib>
#include <climits>
#include <cmath>
#include <ctime>
#include <algorithm>
#include <stack>
#include <sstream>
#include <numeric>
#include <fstream>
#include <functional>

using namespace std;

#define MP make_pair
#define PB push_back
typedef long long LL;
typedef unsigned long long ULL;
typedef vector<int> VI;
typedef pair<int,int> pii;
const int INF = INT_MAX / 3;
const double eps = 1e-8;
const LL LINF = 1e17;
const double DINF = 1e60;
const int maxn = 600;
const int hash_size = 65536;
const unsigned int p_col = 3131, p_row_pos = 1e9 + 7, p_row_val = 2e9 + 17;
char mat[maxn][maxn];
int n,m;
int head[hash_size], nxt[hash_size * 10];
unsigned int val[hash_size * 10], pos_x[hash_size * 10], pos_y[hash_size * 10], sz;
unsigned int pow_col[maxn], pow_row_pos[maxn], pow_row_val[maxn];
unsigned int hc_col[maxn][maxn], hc1[maxn][maxn], hc2[maxn], hc3[maxn];
int ans_x1, ans_x2, ans_y1, ans_y2;

void init() {
    pow_col[0] = pow_row_pos[0] = pow_row_val[0] = 1;
    for(int i = 1;i <= 500;i++) {
        pow_col[i] = p_col * pow_col[i - 1];
        pow_row_pos[i] = p_row_pos * pow_row_pos[i - 1];
        pow_row_val[i] = p_row_val * pow_row_val[i - 1];
    }
}

void init_hc() {
    for(int j = 1;j <= m;j++) {
        for(int i = 1;i <= n;i++) {
            hc_col[i][j] = hc_col[i - 1][j] * p_col + mat[i][j];
        }
    }
}

bool ask(int pos_hash,int val_hash,int x,int y) {
    pos_hash &= (hash_size - 1);
    for(int i = head[pos_hash]; ~i; i = nxt[i]) {
        if(val[i] == val_hash) {
            ans_x1 = pos_x[i];
            ans_y1 = pos_y[i];
            return true;
        }
    }
    pos_x[sz] = x; pos_y[sz] = y;
    val[sz] = val_hash;
    nxt[sz] = head[pos_hash];
    head[pos_hash] = sz++;
    return false;
}

bool ok(int len) {
    //初始化hash表
    memset(head,-1,sizeof(head));
    sz = 0;
    for(int j = 1;j <= m;j++) {
        for(int i = len;i <= n;i++) {
            hc1[i][j] = hc_col[i][j] - hc_col[i - len][j] * pow_col[len];
        }
    }

    for(int i = len;i <= n;i++) {
        hc2[0] = hc3[0] = 0;
        for(int j = 1;j <= m;j++) {
            hc2[j] = hc2[j - 1] * p_row_pos + hc1[i][j] % p_row_pos;
            hc3[j] = hc3[j - 1] * p_row_val + hc1[i][j] % p_row_val;
            if(j >= len) {
                int row_val_hash = hc3[j] - hc3[j - len] * pow_row_val[len],
                    row_pos_hash = hc2[j] - hc2[j - len] * pow_row_pos[len];
                if(ask(row_pos_hash,row_val_hash,i,j)) {
                    ans_x2 = i; ans_y2 = j; return true;
                }
            }
        }
    }
    return false;
}

void solve() {
    init_hc();
    //二分枚举边长
    int l = 1, r = min(n,m), ans = 0;
    while(l <= r) {
        int mid = (l + r) >> 1;
        if(ok(mid)) {
            ans = mid; l = mid + 1;
        }
        else r = mid - 1;
    }
    printf("%d\n",ans);
    if(ans) printf("%d %d %d %d\n",ans_x1 - ans + 1,ans_y1 - ans + 1,ans_x2 - ans + 1,ans_y2 - ans + 1);
}

int main() {
    init();
    while(scanf("%d%d",&n,&m) != EOF) {
        for(int i = 1;i <= n;i++) scanf("%s",mat[i] + 1);
        solve();
    }
    return 0;
}

  

时间: 2024-10-19 09:53:45

URAL 1486 Equal Squares 二维Hash的相关文章

BZOJ1397 Ural 1486 Equal squares

首先二分答案ans,然后只要进行判断答案ans是否可行即可. 验证方法:首先对每一个位置,求出它开始长度为ans的横行的hash值 然后求出每一个hash值的长度为ans的竖列的Hash值 查看是否有两个Hash值相同即可(比如我们可以基数排序...做什么大死!) 1 /************************************************************** 2 Problem: 1397 3 User: rausen 4 Language: C++ 5 Re

BZOJ 1567 Blue Mary的战役地图(二维hash+二分)

题意: 求两个矩形最大公共子正方形.(n<=50) 范围这么小可以枚举子正方形的边长.那么可以对这个矩形进行二维hash,就可以在O(1)的时候求出任意子矩形的hash值.然后判断这些正方形的hash值有没有相同的 部分就行了.可以用二分来判断. 需要注意的是行和列乘的hash种子值需要不同的质数,否则可能出现冲突. 时间复杂度O(n^3logn). # include <cstdio> # include <cstring> # include <cstdlib>

BZOJ 2462 BeiJing 2011 矩阵模板 二维hash

题目大意:给出一个m*n的由01组成的矩阵,下面有q个询问,查询矩阵中存不存在大小为k*l的子矩阵. 思路:二维hash.我们先把大矩阵hash,然后把所有可能的k*l的子矩阵都插到哈希表里,然后只要对于每个询问hash一下看哈希表中是否存在. 值得一提的是,这个题只需要输出10个1就可以AC了.. CODE: #include <cstdio> #include <bitset> #include <cstring> #include <iostream>

弱校联盟10.7 I. Special Squares(二维前缀和)

题目链接: I. Special Squares There are some points and lines parellel to x-axis or y-axis on the plane. If arbitrary chosen two lines parallel to x-axis and two lines parallel to y-axis, one rectangle, or sometimes a square, will be formed. If a square i

[luoguP2601] [ZJOI2009]对称的正方形(二维Hash + 二分 || Manacher)

传送门 很蒙蔽,不知道怎么搞. 网上看题解有说可以哈希+二分搞,也有的人说用Manacher搞,Manacher是什么鬼?以后再学. 对于这个题,可以从矩阵4个角hash一遍,然后枚举矩阵中的点,再二分半径. 但是得考虑边的长度为奇偶所带来的影响. 比如 1 1 1 1 这个边数为偶数的矩阵显然没法搞. 所以得在矩阵中插入0, 变成 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 0 1 0 1 0 0 0 0 0 0 具体操作就看代码好了. 然后只枚举 行 + 列 为偶数的点就行.

BZOJ 1567 JSOI 2008 Blue Mary的战役地图 二维hash

题目大意:给出两个m*m的地图,问两个地图的最大子正方形矩阵的边长是多大. 思路:先对两个矩阵hash,然后枚举最大长度,从大到小枚举.把第一个矩阵的所有情况插到哈希表中,然后查询第二个矩阵的所有情况. 记住哈希表中的那些数组一定要开大点.. CODE: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define MAX 60 #define RA

POJ2002 Squares(二维点哈希)

题目链接: http://poj.org/problem?id=2002 题意: 给定n个点 判断这n个点可以构成多少正方形. 分析: 暴力枚举一条边的两个端点,然后根据全等三角形可以求出可以构成正方形的另外两个边的端点,然后判断这两个两存不存在. 因此首先要把所有的点哈希一下,然后依次暴力枚举,因此四条边都统计了一次 因此最后要除4. 代码如下: #include <iostream> #include <cstdio> #include <algorithm> #i

URAL 1577. E-mail(简单二维dp)

给你两个子串,让你找出来一个最短的字符串包括这两个子串,输出最多的子串有多少种. 类似于最长公共子序列,相等的话长度+1,不想等的话比較长度,使用长度小的. 1577. E-mail Time limit: 1.0 second Memory limit: 64 MB Vasya started to use the Internet not so long ago, so he has only two e-mail accounts at two different servers. For

ural Bicolored Horses(二维dp)

http://acm.timus.ru/problem.aspx?space=1&num=1167 有n个马,黑白两种,依次放入k个马厩,将x匹马放在一个马厩的不快乐值为黑马数目*白马数目.问最后的不快乐值最小是多少? 设dp[i][j]表示前i个马厩放了j匹马的最小不快乐值,那么dp[i][j] = min(dp[i-1][g]+tmp[g+1][j]). 其中tmp是预处理的i到j匹马的不快乐值. #include <stdio.h> #include <iostream&g