YBTOJ 哈希合集

qwq

哈希是个神奇的东西,因为从来没有老师讲而默认我们需要会?咕咕咕

字符串哈希

模板略。

回文字串

分别求哈希前缀和以及哈希后缀和,枚举每一个位置作为回文串中点,对回文串长度分奇偶讨论一下,分别二分长度即可。

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define ff(i,s,e) for(int i(s);i<=(e);++i)
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=1e6+5;
const int base=131,mod=1e9+7;
char s[N];
ull a[N],b[N],mi[N];
inline int solve(){
	int n=strlen(s+1);
	memset(a,0,sizeof(a));
	memset(b,0,sizeof(b));
	ff(i,1,n) a[i]=(a[i-1]*base+s[i])%mod;
	for(int i=n;i;--i) b[i]=(b[i+1]*base+s[i])%mod;
	int ans=1;
	ff(i,2,n-1){
		int l,r,res;
		if(s[i]==s[i+1]){
			l=1,r=min(i,n-i);
			while(l<=r){
				int mid=l+r>>1;
				ull x=(a[i]-a[i-mid]*mi[mid]%mod+mod)%mod,y=(b[i+1]-b[i+mid+1]*mi[mid]%mod+mod)%mod;
				if(x==y) l=mid+1,res=mid;
				else r=mid-1;
			}
			ans=max(ans,res<<1);
		}
		l=1,r=min(i-1,n-i),res=0;
		while(l<=r){
			int mid=l+r>>1;
			ull x=(a[i-1]-a[i-mid-1]*mi[mid]%mod+mod)%mod,y=(b[i+1]-b[i+mid+1]*mi[mid]%mod+mod)%mod;
			if(x==y) l=mid+1,res=mid;
			else r=mid-1;
		}
		ans=max(ans,res<<1|1);
	}
	return ans;
}
signed main(){
	mi[0]=1;
	ff(i,1,(int)1e6) mi[i]=mi[i-1]*base%mod;
	for(int t=1;;++t){
		scanf("%s",s+1);
		if(s[1]=='E') return 0;
		printf("Case %d: %d\n",t,solve());
	}
}

对称正方形

二维哈希模板,存一个原矩阵,一个上下颠倒矩阵,一个左右颠倒矩阵,分别哈希预处理。然后枚举对称正方形中心点,分正方形边长分奇偶分别二分求判断是否对称即可。二维哈希查询也一个容斥就搞出来了。时间复杂度 O ( n 2 l o g n ) O(n^2logn) O(n2logn)

很简单是吧,为什么连着写了两个晚上才写过呢,因为忘了矩阵颠倒之后原矩阵的 ( x , y ) (x,y) (x,y) 位置也变了啊啊啊啊我是什么制杖

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
#define ll long long
#define ff(i,s,e) for(int i(s);i<=(e);++i)
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int basex=131,basey=313,N=1005;
int n,m;
ull a[N][N],b[N][N],c[N][N],mix[N],miy[N];
inline void ha(){
	mix[0]=miy[0]=1;
	ff(i,1,max(m,n)){
		mix[i]=mix[i-1]*basex;
		miy[i]=miy[i-1]*basey;
	}
	ff(i,1,n) ff(j,1,m){
		a[i][j]=a[i][j-1]*basey+a[i][j];
		b[i][j]=b[i][j-1]*basey+b[i][j];
		c[i][j]=c[i][j-1]*basey+c[i][j];
	}
	ff(i,1,n) ff(j,1,m){
		a[i][j]=a[i-1][j]*basex+a[i][j];
		b[i][j]=b[i-1][j]*basex+b[i][j];
		c[i][j]=c[i-1][j]*basex+c[i][j];
	}
}
inline bool check(int x1,int y1,int x2,int y2){
	if(x1<1||y1<1||x2>n||y2>m) return 0;
	ull x=a[x2][y2]-a[x2][y1-1]*miy[y2-y1+1]-a[x1-1][y2]*mix[x2-x1+1]+a[x1-1][y1-1]*mix[x2-x1+1]*miy[y2-y1+1];
	int x11=n-x2+1,x22=n-x1+1;//一定不要忘!!! 
	ull y=b[x22][y2]-b[x22][y1-1]*miy[y2-y1+1]-b[x11-1][y2]*mix[x22-x11+1]+b[x11-1][y1-1]*mix[x22-x11+1]*miy[y2-y1+1];
	int y11=m-y2+1,y22=m-y1+1;
	ull z=c[x2][y22]-c[x2][y11-1]*miy[y22-y11+1]-c[x1-1][y22]*mix[x2-x1+1]+c[x1-1][y11-1]*mix[x2-x1+1]*miy[y22-y11+1];
	return (x==y)&&(x==z);
}
signed main(){
	n=read(),m=read();
	ff(i,1,n) ff(j,1,m) a[i][j]=b[n-i+1][j]=c[i][m-j+1]=read();
	ha();
	int ans=0;
	ff(i,1,n) ff(j,1,m){
		int l=0,r=min(m,n),res=0;
		while(l<=r){
			int mid=l+r>>1;
			if(check(i-mid,j-mid,i+mid,j+mid)) l=mid+1,res=mid;
			else r=mid-1;
		}
		ans+=res+1,l=1,r=min(m,n),res=0;
		while(l<=r){
			int mid=l+r>>1;
			if(check(i-mid+1,j-mid+1,i+mid,j+mid)) l=mid+1,res=mid;
			else r=mid-1;
		}
		ans+=res;
	}
	printf("%d",ans);
	return 0;
}

单词背诵

哈希存要背的单词,通过哈希比较看有几个单词出现在文章中,然后通过尺取法找最小长度即可。(为什么以前会以为尺取法是个很高深的东西啊/kk

要特判文章里没有单词的情况,第二个直接输出0。

子正方形

想到和T3类似的思路,先分别将两个矩阵哈希一遍,再在第一个矩阵里枚举每一个点作为正方形的中心位置,二分正方形边长,在第二个矩阵里寻找是否存在哈希值一样的正方形即可。时间复杂度 O ( n 4 l o g n ) O(n^4logn) O(n4logn)

话说我自己口胡完拿计算器敲了一下这个复杂度发现是八位数,以为是 3 e 8 3e8 3e8 不可过,自我怀疑了一会发现八位数是 3 e 7 3e7 3e7?我什么时候才能学会数数/kk

#include<cstdio>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
#define ll long long
#define ff(i,s,e) for(int i(s);i<=(e);++i)
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=55,basex=131,basey=313;
int n;
ull a[N][N],b[N][N],mix[N],miy[N];
inline void ha(){
	mix[0]=miy[0]=1;
	ff(i,1,n){
		mix[i]=mix[i-1]*basex;
		miy[i]=miy[i-1]*basey;
	}
	ff(i,1,n) ff(j,1,n){
		a[i][j]=a[i][j-1]*basey+a[i][j];
		b[i][j]=b[i][j-1]*basey+b[i][j];
	}
	ff(i,1,n) ff(j,1,n){
		a[i][j]=a[i-1][j]*basex+a[i][j];
		b[i][j]=b[i-1][j]*basex+b[i][j];
	}
}
inline bool check(int x1,int y1,int x2,int y2){
	if(x1<1||y1<1||x2>n||y2>n) return 0;
	int len=x2-x1+1;
	ull x=a[x2][y2]-a[x2][y1-1]*miy[y2-y1+1]-a[x1-1][y2]*mix[x2-x1+1]+a[x1-1][y1-1]*mix[x2-x1+1]*miy[y2-y1+1];
	for(x1=1;x1<=n-len+1;++x1) for(y1=1;y1<=n-len+1;++y1){
		x2=x1+len-1,y2=y1+len-1;
		ull y=b[x2][y2]-b[x2][y1-1]*miy[y2-y1+1]-b[x1-1][y2]*mix[x2-x1+1]+b[x1-1][y1-1]*mix[x2-x1+1]*miy[y2-y1+1];
		if(y==x) return 1;
	} 
	return 0;
}
signed main(){
	n=read();
	ff(i,1,n) ff(j,1,n) a[i][j]=read();
	ff(i,1,n) ff(j,1,n) b[i][j]=read();
	ha();
	int ans=0;
	ff(i,1,n) ff(j,1,n){
		int l=0,r=n,res=0;
		while(l<=r){
			int mid=l+r>>1;
			if(check(i-mid,j-mid,i+mid,j+mid)) res=mid,l=mid+1;
			else r=mid-1;
		}
		ans=max(ans,res<<1|1);
		l=1,r=n,res=0;
		while(l<=r){
			int mid=l+r>>1;
			if(check(i-mid+1,j-mid+1,i+mid,j+mid)) res=mid,l=mid+1;
			else r=mid-1;
		}
		ans=max(ans,res<<1);
	}
	printf("%d",ans);
	return 0;
}

特殊数列

哈希表模板略。

求好元素

O ( n 2 ) O(n^2) O(n2) 预处理出 a m + a n a_m+a_n am+an 的所有值并哈希,再 O ( n 2 ) O(n^2) O(n2)枚举 i i i p p p,在哈希表中查找即可。

什么毒瘤卡常题啊,vector永远8000多msTLE,改链前就2000多?/kk

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define ff(i,s,e) for(int i(s);i<=(e);++i)
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=5005,mod=1e7+7;
int n,a[N];
int head[mod+2],cnt;
struct qwq{
    int v,nxt;
}e[N*N];
inline void add(int u,int v){
    e[++cnt]=qwq{v,head[u]},head[u]=cnt;
}
inline int ha(int x){
	int res=x%mod+mod;
    if(res>=mod) res-=mod;
    return res;
}
inline bool check(int i,int val){
	for(int j=head[i];j;j=e[j].nxt){
        int v=e[j].v;
        if(v==val) return 1;
    }
	return 0;
}
signed main(){
	n=read();
	ff(i,1,n) a[i]=read();
	int ans=0;
	ff(i,1,n){		
        int flag=0;
		ff(j,1,i-1){
			int val=a[i]-a[j],qwq=ha(val);
			if(check(qwq,val)){flag=1;break;}
		}
		if(flag) ++ans;
		ff(j,1,i){
			int val=a[i]+a[j],qwq=ha(val);
			if(!check(qwq,val)) add(qwq,val);
		}
	}
	printf("%d",ans);
	return 0; 
} 

上课点名

今天是哈希冲突人呢

b a s e = 131 base=131 base=131 m o d = 1 e 7 + 7 mod=1e7+7 mod=1e7+7 冲突成70pts,一顿魔改vector套pair最后没卡常卡着时限过了。

最大分离度

每个人对应一个点,直接有边的两个人之间边权为1,跑一遍floyd即可。

看到50的数据范围可以偷个懒写map也跑的1飞飞快/kx

多测清空啊qwq

回文分区

奇奇怪怪的乱搞,从两边往中间扫,发现前后有一段相同就计入答案,中间的位置要特判一下。

#include<bits/stdc++.h>
#define ull unsigned long long
#define ll long long
#define ff(i,s,e) for(int i(s);i<=(e);++i)
using namespace std;
inline int read(){
	int x=0,f=1;
	char ch=getchar();
	while(ch>'9'||ch<'0'){if(ch=='-') f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
	return x*f;
}
const int N=1e6+5,base=131;
char s[N];
ull a[N],mi[N];
inline void solve(){
    scanf("%s",s+1);
    int n=strlen(s+1);
    ff(i,1,n) a[i]=a[i-1]*base+s[i];
    int ans=0;
    for(int st=1,ed=n;st<=ed;++st,--ed){
        int len,pre=ed-st+1;
        for(len=1;len<=pre;++len){
           ull x=a[st+len-1]-a[st-1]*mi[len];
           ull y=a[ed]-a[ed-len]*mi[len];
           if(x==y) break;
        }
        ans+=2,st+=len-1,ed-=len-1;
        if(st==ed-1) break;//特判一下正好的情况
        if(st>=ed){--ans;break;}//中间一段不能形成回文的情况
    }
    printf("%d\n",ans);
}
signed main(){
    mi[0]=1;
    ff(i,1,(int)1e6) mi[i]=mi[i-1]*base;
    int T=read();
    while(T--) solve();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值