URAL - 1486 二维字符串HASH

 

题目链接:http://acm.timus.ru/problem.aspx?space=1&num=1486

题意:给定一个n*m的字符矩阵,问你是否存在两个不重合(可以有交集)的正方形矩阵完全一致, 存在输出正方形的最大边长和两个正方形的左上角坐标,不存在则输出0

思路:二维字符串Hash,二分正方形的长度,然后Hash判断即可。

 

#define _CRT_SECURE_NO_DEPRECATE
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<map>
#include<vector>
#include<time.h>
#include<stack>
#include<cmath>
using namespace std;
typedef long long int LL;
typedef unsigned long long int ULL;
const int MAXN = 500 + 24;
const ULL pr =  9973;
const ULL pc =  100000007;
char str[MAXN][MAXN];
pair<int, int>ans1, ans2;
map<ULL, pair<int, int>>mp;
ULL Hash[MAXN][MAXN];
bool check(int n,int m,int x){
    mp.clear();
    ULL t1 = 1;
    for (int i = 0; i < x; i++){
        t1 *= pr;
    }
    for (int i = 0; i < n; i++){
        ULL e = 0;
        for (int j = 0; j < x; j++){
            e = e*pr + (str[i][j] - 'a');
        }
        for (int j = 0; j + x <= m; j++){
            Hash[i][j] = e;
            if (j + x < m){
                e = e*pr - t1*(str[i][j] - 'a') + (str[i][j + x] - 'a');
            }
        }
    }

    ULL t2 = 1;
    for (int i = 0; i < x; i++){
        t2 *= pc;
    }
    for (int j = 0; j+x <= m; j++){
        ULL e = 0;
        for (int i = 0; i < x; i++){
            e = e*pc + Hash[i][j];
        }
        for (int i = 0; i + x <= n; i++){
            if (mp.find(e) != mp.end()){
                ans1 = mp[e];
                ans2.first = i, ans2.second = j;
                return true;
            } 
            mp.insert(make_pair(e, make_pair(i, j)));
            if (i + x < n){
                e = e*pc - t2*Hash[i][j] + Hash[i + x][j];
            }
        }
    }
    return false;
}
int main(){
//#ifdef kirito
//    freopen("in.txt", "r", stdin);
//    freopen("out.txt", "w", stdout);
//#endif
//    int start = clock();
    int n, m; 
    while (~scanf("%d%d", &n,&m)){
        for (int i = 0; i < n; i++){
            scanf("%s", str[i]);
        }
        int l = 1, r = min(n, m), mid;
        while (r >= l){
            mid = (r + l) >> 1;
            if (check(n,m,mid)){
                l = mid + 1;
            }
            else{
                r = mid - 1;
            }
        }
        if (r&&check(n,m,r)){
            printf("%d\n", r);
            printf("%d %d\n", ans1.first + 1, ans1.second + 1);
            printf("%d %d\n", ans2.first + 1, ans2.second + 1);
        }
        else{
            printf("0\n");
        }
    }
//#ifdef LOCAL_TIME
//    cout << "[Finished in " << clock() - start << " ms]" << endl;
//#endif
    return 0;
}

 

posted @ 2017-06-29 19:24  キリト  阅读(323)  评论(0编辑  收藏  举报