「 「 「字符串算法 」 」 」第 2 2 2章 H a s h Hash Hash和 H a s h Hash Hash表 ( ( (后 2 2 2题 ) ) )
前半章 l i n k link link
目录:
D.单词背诵
E.子正方形
D . D. D. 例题 4 4 4 单词背诵
分析:
用 a [ ] , b [ ] a[],b[] a[],b[]两数组表示输入的 n n n个单词 和 m m m段单词 思路就是扫描整体段落 找最优段落
过程:
给 a [ ] , b [ ] a[],b[] a[],b[]每个单词一个 h a s h hash hash值 这样就一个字符串哈希解决 然后给它标记
然后根据这个标记 看 a [ ] a[] a[]的标记跟 b [ ] b[] b[]的标记一样 就可以求出要背几个单词q ( a [ ] (a[] (a[]与 b [ ] b[] b[]是不同数组存标记 ) ) )
还要考虑怎么找最优段落 用左右端点对段落扫描
用一个 u p d [ ] upd[] upd[]数组记录一下 a [ ] a[] a[]单词在当前 [ l , r ] [l,r] [l,r]中出现的次数
如果这是初次出现 那么出现单词种类 p p p就 + + ++ ++ 同时该单词次数 + + ++ ++
看 p p p和 q q q是否相等 相等就说明当前段落已经包括了所有 b [ ] b[] b[]的目标单词
这时就要存储最优解 a n s ans ans了 然后看单词是不是目标单词 或重复出现 都先舍去 ( r − − ) (r--) (r−−)
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=5e6+5;
const int base=131;
const long long p=1499993;
int n,m,fad,ans=0x3f3f3f3f,l,r,cnt;
char qwq[33];
int a[N],b[N],upd[N],Ap[N],ovo[N];
int Hash(char qaq[])
{
int len=strlen(qaq),ret=0;
for(int i=0;i<len;i++)
ret=(ret*base+qaq[i])%p; //哈希
return ret;
}
int main(){
scanf("%d",&n);
for(reg int i=1;i<=n;i++)
{
cin>>qwq;
a[i]=Hash(qwq);
ovo[a[i]]=1;
}
scanf("%d",&m);
for(reg int i=1;i<=m;i++)
{
cin>>qwq;
b[i]=Hash(qwq);
if(ovo[b[i]]&&!Ap[b[i]]) //看要背几个单词
{
fad++;
Ap[b[i]]=1;
}
}
if(fad==0){
printf("0\n0"); return 0;}
else printf("%d\n",fad);
l=r=m;
while(1)
{
if(cnt==fad){
//包括所有目标单词
while(!Ap[b[r]]) r--;
ans=min(ans,r-l); //取区间长度
if(upd[b[r]]>=1)
{
if(upd[b[r]]==1) fad++;
upd[b[r]]--; r--;
}
}
else{
if(l==0) break;
if(Ap[b[l]])
{
if(!upd[b[l]]) cnt++;
upd[b[l]]++;
}
l--;
}
}
printf("%d",ans);
return 0;
}
E . E. E. 例题 5 5 5 子正方形
分析:
这道题范围仅 50 50 50 可以直接暴搜 + H a s h +Hash +Hash 就可以过辽
判断矩阵是否相等 以及把矩阵做 H a s h Hash Hash 跟 l i n k link link的 C C C题差不多 具体看这个吧
然后就可以 4 4 4重 f o r for for来把二分矩阵的大小 最后取 m a x max max即可
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=55;
const ull p1=131,p2=313;
int n,A[N][N],B[N][N],l,r,mid,ans,temp;
ull Base_A[N],Base_B[N],Hash_A[N][N],Hash_B[N][N];
void Hash_Work() //矩阵hash
{
Base_A[0]=Base_B[0]=1ull;
for(reg int i=1;i<=n;i++)
Base_A[i]=Base_A[i-1]*p1;
for(reg int i=1;i<=n;i++)
Base_B[i]=Base_B[i-1]*p2;
for(reg int i=1;i<=n;i++)
for(reg int j=1;j<=n;j++)
{
Hash_A[i][j]=Hash_A[i][j-1]*p1+A[i][j];
Hash_B[i][j]=Hash_B[i][j-1]*p1+B[i][j];
}
for(reg int i=1;i<=n;i++)
for(reg int j=1;j<=n;j++)
{
Hash_A[i][j]+=Hash_A[i-1][j]*p2;
Hash_B[i][j]+=Hash_B[i-1][j]*p2;
}
}
bool check(int sx,int sy,int ex,int ey,int mid)
{
ull val1=Hash_A[sx][sy]-Hash_A[sx][sy-mid]*Base_A[mid]-Hash_A[sx-mid][sy]*Base_B[mid]+Hash_A[sx-mid][sy-mid]*Base_A[mid]*Base_B[mid];
ull val2=Hash_B[ex][ey]-Hash_B[ex][ey-mid]*Base_A[mid]-Hash_B[ex-mid][ey]*Base_B[mid]+Hash_B[ex-mid][ey-mid]*Base_A[mid]*Base_B[mid];
return val1==val2; //判断矩阵相等
}
void work()
{
for(reg int St_x=1;St_x<=n;St_x++)
for(reg int St_y=1;St_y<=n;St_y++)
for(reg int Ed_x=1;Ed_x<=n;Ed_x++)
for(reg int Ed_y=1;Ed_y<=n;Ed_y++) //枚举矩阵
{
l=0;r=min(min(St_x,St_y),min(Ed_x,Ed_y));
temp=0;
while(l<=r)
{
mid=(l+r)>>1;
if(check(St_x,St_y,Ed_x,Ed_y,mid))
{
temp=mid;
l=mid+1;
}else
r=mid-1;
}
ans=max(ans,temp);
}
}
int main(){
scanf("%d",&n);
for(reg int i=1;i<=n;i++)
for(reg int j=1;j<=n;j++)
scanf("%d",&A[i][j]);
for(reg int i=1;i<=n;i++)
for(reg int j=1;j<=n;j++)
scanf("%d",&B[i][j]);
Hash_Work();
work();
printf("%d",ans);
return 0;
}