URAL 1486(二维字符串hash)

题意:一个最大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;
}
时间: 2024-10-06 03:36:45

URAL 1486(二维字符串hash)的相关文章

编程题:用二维字符串数组实现。从键盘输入三个学生姓名,并输出。

#include<stdio.h> #include<string.h> void main() { char name[3][30]; int i; for(i=0;i<3;i++) gets(name[i]);  /*name[i]是一个一维字符数组*/ for(i=0;i<3;i++) printf("%s\n",name[i]); } 编程题:用二维字符串数组实现.从键盘输入三个学生姓名,并输出.,布布扣,bubuko.com

201/7/31-zznuoj-问题 A: A + B 普拉斯【二维字符串+暴力模拟+考虑瑕疵的题意-0的特例】

问题 A: A + B 普拉斯 在计算机中,数字是通过像01像素矩阵来显示的,最终的显示效果如下:  现在我们用01来构成这些数字 当宝儿姐输入A + B 时(log10(A)<50,log10(B)<50,且A,B均为正整数),你来计算A+B的和C,并按格式在屏幕上打印C. 输入 每组输入包括两个非负整数 A,B(log10(A)<50,log10(B)<50),已EOF结束输入 输出 按格式在屏幕中打印C,数字之间相隔三列0. 样例输入 3 8 样例输出 00100000001

定义一个二维字符串数组,存储5个身份证号码,并输出

#include<stdio.h> #include<stdlib.h> int main() { int i; char str[][20]={"441431196908236539","441411199703251825","441421199908236536","331421199908236530","461621199908236535"}; for(i=0;i<

字符串分割到二维字符数组中:

/* *字符串分割,把一个长的字符串(可能有空格),分割到一个二维字符数组中. *并且输出 * *时间复杂度O(N) *注意在操作二维字符串数组时:使用"数组指针"操作能方便 int(*p)[LEN]; * */ #include<stdio.h> #include<string.h> #include<stdlib.h> #include<stdbool.h> #define NDEBUG #include<assert.h>

【URAL 1486】Equal Squares

题意:求给定字符矩阵中相同正方形矩阵的最大边长和这两个相同正方形的位置 第一次写字符串哈希,选两个不同的模数进行二维字符串哈希. 本来应该取模判断相等后再暴力扫矩阵来判断,但是我看到<Hash在信息学竞赛中的一类应用>中这么写道: 于是我还会再次判重吗?肯定不会!!! 于是这样写完后就调啊调,调出几个像没用unsigned long long这样的脑残错误后交上去就A了233 #include<cstdio> #include<cstring> #include<

POJ 2185 二维KMP

题意:就是让你求出最小的字符矩阵面积,这个矩阵是这个大矩阵里能够循环的,但是并不一定是全部循环相同的,部分相同也算循环,比如样例. 思路:这题挺好的,以前没有想到二维字符串数组也可以用next数组求出其循环节,现在这题正好补了这个空. 解法:把每一个字符串当做字符进行求next数组,然后求出最小的循环字符串长度,即:len-next[len].因为以前求循环节是len/(len-next[len]),括号里面的不就是最小的循环长度嘛! 因为要求这个循环矩阵的长和宽,所以长就是每一行作为一个字符串

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 &

二维数组(扩展hash数组)以及json,严格模式,字符串的常用api

二维数组 数组中的每一个元素也是数组 ?var arr=[ [1,2,3], [4,5,6], [7,8,9], [1,2,3,4,5,6,7] ...]; 怎么遍历二维数组 var arr=[ [1,2,3], [4,5,6,7], [10,20,30,40,60,80] ]; for(var r=0;r<arr.length;r++){ for(var c=0;c<arr[r].length;c++){ console.log(arr[r][c]); } } 怎么访问二维数组中的元素 ar

[CSP-S模拟测试]:回文(hash+二维前缀和)

题目描述 闲着无聊的$YGH$秒掉上面两道题之后,开始思考有趣的回文串问题了. 他面前就有一个漂浮着的字符串.显然$YGH$是会$manacher$的,于是他随手求出了这个字符串的回文子串个数.但是他不满足于这个问题,他打算搞出一个数据结构,能够快速求出这个字符串下标为$[l,r]$的子串的回文子串个数(相同的回文子串需重复计数).但是这实在是太简单啦,他打算考考辣鸡$YYR$,可是辣鸡至极的$YYR$完全没有思路. 于是,$YGH$扬长而去,在衣袖带起的一小片尘土之中,沉思的$YYR$依旧在那