【Ybt OJ】[字符串算法 第2章] 哈希Hash [后半章]

「 「 字符串算法 」 」 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 单词背诵

洛谷 l i n k link link
在这里插入图片描述
在这里插入图片描述

分析:

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;
}

猜你喜欢

转载自blog.csdn.net/dgssl_xhy/article/details/113005443
今日推荐