URAL 1486(二维字符串hash)

来源:互联网 发布:刚性攻丝编程 编辑:程序博客网 时间:2024/05/21 20:26

题意:一个最大500*500的字符矩阵,求最大的两个相同的字符正方形。正方形可以有重叠部分但不能重合。


解法:首先是二分正方形的长度,然后判断某个长度存在时候计算字符矩阵的二维hash值,二维hash的方法是:


这样子拓展的hash算法可以O(1) 获取任意一个子矩阵的hash值。


代码:

/******************************************************* @author:xiefubao*******************************************************/#pragma comment(linker, "/STACK:102400000,102400000")#include <iostream>#include <cstring>#include <cstdlib>#include <cstdio>#include <queue>#include <vector>#include <algorithm>#include <cmath>#include <map>#include <set>#include <stack>#include <string.h>//freopen ("in.txt" , "r" , stdin);using namespace std;#define eps 1e-8#define zero(_) (abs(_)<=eps)const double pi=acos(-1.0);typedef unsigned long long LL;const int Max=502;const LL INF=100007;char s[Max][Max];LL hash[Max][Max];LL hash2[Max][Max];LL scale[Max];LL scale2[Max];LL seed=3131;LL seed2=1313;int n,m;int count1=0;struct edge{    LL data;    int next;    int x,y;} edges[Max*Max];int head[100010];int tot=0;void add(LL u,LL data,int x,int y){    edges[tot].data=data;    edges[tot].x=x;    edges[tot].y=y;    edges[tot].next=head[u];    head[u]=tot++;}int have(LL value){    LL t=value%INF;    for(int i=head[t];i!=-1;i=edges[i].next)    {        if(edges[i].data==value)        return i+1;    }    return 0;}bool OK(int t){    memset(head,-1,sizeof head);    tot=0;    for(int i=1; i+t-1<=n; i++)        for(int j=1; j+t-1<=m; j++)        {            LL value=0;            value=hash2[i+t-1][j+t-1]-hash2[i+t-1][j-1]*scale[t]-hash2[i-1][j+t-1]*scale2[t]+hash2[i-1][j-1]*scale[t]*scale2[t];            if(have(value))            return true;            add(value%INF,value,i,j);        }    return false;}void solve(int t){    memset(head,-1,sizeof head);    tot=0;    for(int i=1; i+t<=n+1; i++)        for(int j=1; j+t<=m+1; j++)        {            LL value=0;            value=hash2[i+t-1][j+t-1]-hash2[i+t-1][j-1]*scale[t]-hash2[i-1][j+t-1]*scale2[t]+hash2[i-1][j-1]*scale[t]*scale2[t];            int ok=have(value);            if(ok)            {             cout<<edges[ok-1].x<<" "<<edges[ok-1].y<<endl;             cout<<i<<" "<<j<<endl;             return ;            }            else            add(value%INF,value,i,j);        }}int main(){    while(cin>>n>>m)    {        scale[0]=1;        scale2[0]=1;        for(int i=1; i<Max; i++)            scale[i]=scale[i-1]*seed,scale2[i]=scale2[i-1]*seed2;        for(int i=1; i<=n; i++)            for(int j=1; j<=m; j++)                cin>>s[i][j];        for(int i=1; i<=n; i++)            for(int j=1; j<=m; j++)            {                hash[i][j]=hash[i][j-1]*seed+s[i][j];                hash2[i][j]=hash2[i-1][j]*seed2+hash[i][j];            }        int left=1;        int right= n==m?n-1:min(n,m);        while(left<=right)        {            int middle=(left+right)/2;            if(OK(middle))                left=middle+1;            else                right=middle-1;        }        if(right==0)            cout<<right<<endl;        else        {            cout<<right<<endl;            solve(right);        }    }    return 0;}

0 0