bzoj1170 [Balkan2007]Cipher

本文介绍了一种通过简单的字符串哈希方法来找出字符矩阵中出现次数最多的指定大小的子矩阵的方法。文章详细展示了如何利用哈希表进行高效查找,并提供了完整的C++实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/archives/2908
Description

给出一个字符矩阵,你要从中找出一个出现次数最多的子矩阵.

Input

第一行给出N,M.代表矩阵的大小. 下面N行M列用来描述矩阵的形态. 再给出X,Y代表子矩阵的大小.

Output

先输出X,Y 再输出你所找到的字符矩阵. 再输出它出现的次数. 再输出它每次出现的位置的左上角坐标.

Sample Input

8 10
qw.aba..f.
wq.bab.ff.
zx.cdc.K.R
c.ababa.es
x.babab.Ed
j.cdcdcaba
yo.k.k.bab
opu..l.cdc
3 3
Sample Output

3 3
aba
bab
cdc
4
1 4
4 3
4 5
6 8
HINT

Source

只要简单的字符串hash即可 注意读入方式需要严格遵照蒟蒻我这样 ..要来数据之后发现这辣鸡读入.. 算出hash值 然后遍历hash值里找一下出现次数最大的 针对每个hash值都开一个vector储存位置在哪里

#include<map>
#include<vector>
#include<queue>
#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1100
#define g1 11113
#define g2 11117
#define pi make_pair
#define pa pair<int,int>
#define ll unsigned long long
using namespace std;
map<ll,int>::iterator it;
int cnt;map<ll,int> mm1,mm2;
vector<pa> ans[1000010];char s[N][N];
ll hs[N][N],p1[N],p2[N];int n,m,x,y; 
inline int read(){
    int x=0,f=1;char ch=getchar();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=getchar();
    return x*f;
}
int main(){
    freopen("bzoj1170.in","r",stdin);
    scanf("%d %d\n",&n,&m);p1[0]=p2[0]=1;
    for (int i=1;i<=n;++i){
        fread(s[i]+1,m+1,1,stdin);
        for (int j=1;j<=m;++j) 
            hs[i][j]=hs[i][j-1]*g1+s[i][j];
        for (int j=1;j<=m;++j) hs[i][j]+=hs[i-1][j]*g2;
    }for (int i=1;i<=n;++i) p2[i]=p2[i-1]*g2;
    for (int i=1;i<=m;++i) p1[i]=p1[i-1]*g1;x=read();y=read();
    for (int i=x;i<=n;++i){
        for (int j=y;j<=m;++j){ll tmp=0;int id;
            tmp+=hs[i][j]+hs[i-x][j-y]*p1[y]*p2[x];
            tmp-=hs[i-x][j]*p2[x]+hs[i][j-y]*p1[y];
            ++mm1[tmp];if (!mm2[tmp]) mm2[tmp]=++cnt,id=cnt;else id=mm2[tmp];
            ans[id].push_back(pi(i-x+1,j-y+1)); 
        }
    }int mx=0;ll hs1;
    for (it=mm1.begin();it!=mm1.end();++it) if(it->second>mx) mx=it->second,hs1=it->first;
    printf("%d %d\n",x,y);int id=mm2[hs1],stx=ans[id][0].first,sty=ans[id][0].second;
    for (int i=stx;i<stx+x;++i){
        for (int j=sty;j<sty+y;++j) putchar(s[i][j]);puts("");
    }printf("%d\n",mx);
    for (int i=0;i<ans[id].size();++i) printf("%d %d\n",ans[id][i].first,ans[id][i].second);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值