hash小结

这个简单且好写

裸的带题面得hash懒得找,找了个板子

给定一个长n的字符串txt和一个长m的字符串str,问txt里能不能找到str;

考虑暴力,O(nm)逐个比对,如果要比对总共k个字符串就是O(nmk),会炸

考虑优化。

#include<bits/stdc++.h>
#define MAXN 10001 
#define ull unsigned long long
using namespace std;
ull mod=212370440130137957ll;
const int p=131;
ull has[MAXN];
ull prime=233317;
int n,t,ans=1;
char str[MAXN];
int main(){
	scanf("%d",&n);
	t=n;
	for(int j=1;j<=n;j++){
		scanf("%s",str+1);
		int l=strlen(str+1);
		ull hs=0;
		for(int i=1;i<=l;i++)hs=((hs*p)%mod+(ull)str[i]+prime)%mod;
		has[j]=hs;
	}
	sort(has+1,has+n+1);
	for(int i=1;i<n;i++)if(has[i]!=has[i+1])ans++;
	printf("%d",ans);
	return 0;
}

由于这个东西不算一个算法,算是字符串的处理技巧,所以基本上都会辅佐其他算法使用

比如说二分

使用二分答案尝试最长的序列,比对时使用hash快速匹配

#include<bits/stdc++.h>
#define MAXN 501
#define ull unsigned long long
using namespace std;
ull p=13331;
int n,m,ans;
char c1[MAXN][MAXN],c2[MAXN][MAXN];
ull pw[MAXN];
ull has1[MAXN][MAXN],has2[MAXN][MAXN];
map<ull,bool>mp;
bool check(int p){
	for(int l=1,r=l+p-1;r<=m;r++,l++){
		bool f=1;
		mp.clear();
		for(int i=1;i<=n;i++)mp[has1[i][r]-has1[i][l-1]*pw[r-l+1]]=1;
		for(int i=1;i<=n;i++)if(mp[has2[i][r]-has2[i][l-1]*pw[r-l+1]]){f=0;break;}
		if(f)return 1;
	}
	return 0;
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)scanf("%s",c1[i]+1);
	for(int i=1;i<=n;i++)scanf("%s",c2[i]+1);
	pw[0]=1;
	for(int i=1;i<=MAXN;i++)pw[i]=pw[i-1]*p;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=m;j++){
			has1[i][j]=has1[i][j-1]*p+c1[i][j];
			has2[i][j]=has2[i][j-1]*p+c2[i][j];
		}
	}
	int l=1,r=m;
	while(l<=r){
		int mid=l+r>>1;
		if(check(mid))ans=mid,r=mid-1;
		else l=mid+1;
	}
	printf("%d",ans);
	return 0;
}

或者说DP

推方程即可,例如本题中设dp[i][j]为到i个氨基酸而该放置第k位时的最优解,很容易得到方程。

	for(int i=0;i<=lt;i++)dp[0][i]=1,has[i]=has[i-1]*p+txt[i];
	for(int t=1,u;t<=k;t++){
		scanf("%d",&u);
		while(u--){
			scanf("%s",str+1);
			ls=strlen(str+1);
			ull hs=0;
			for(int i=1;i<=ls;i++)hs=hs*p+str[i];
			for(int l=1,r=l+ls-1;r<=lt;l++,r++){
				if(hs==get(l,r))dp[t][r]=(dp[t][r]+dp[t-1][l-1])%mod;
			}
		}
	}
	for(int i=1;i<=lt;i++)ans=(ans+dp[k][i])%mod;
	printf("%d",ans);

由于不一定要配出完整的序列,最后将dp[k][i]累加即可。

数据结构结合等。

手写一个栈,如果栈顶ls长度的串的hash与str的hash相等就弹栈,弹到不能再弹为止,每次顺便将txt的栈顶位加入答案,输出即可。教练要求用kmp写不过我太菜就先用hash水AC了

#include<bits/stdc++.h>
#define ull unsigned long long
#define MAXN 1000005
using namespace std;
char txt[MAXN],str[MAXN],ans[MAXN];
int lt,ls;
int p=131;
ull pw[MAXN];
ull hast[MAXN],hass;
ull stk[MAXN];
int top;
int main(){
	scanf("%s%s",txt+1,str+1);
	lt=strlen(txt+1),ls=strlen(str+1);
	pw[0]=1;
	for(int i=1;i<=MAXN;i++)pw[i]=pw[i-1]*p;
	for(int i=1;i<=ls;i++)hass=hass*p+str[i];
	for(int i=1;i<=lt;i++){
		ans[++top]=txt[i];
		stk[top]=stk[top-1]*p+txt[i];
		if(top>=ls&&stk[top]-pw[ls]*stk[top-ls]==hass)top-=ls;
	}
	for(int i=1;i<=top;i++)printf("%c",ans[i]);
	return 0;
}

hash+二分+区间维护

动物园&周期
枚举左端点l,二分右端点r,通过check后更新[l,r]的信息即可。

#include<bits/stdc++.h>//OKRperiod
#define MAXN 1000005//Hash&Binary&SegmentTree
#define ull unsigned long long
#define int long long
using namespace std;
int n,lt,ans;
char txt[MAXN];
ull has[MAXN],pw[MAXN];
const int p=131;
bool check(int l,int r){
	return has[r-l+1]==has[r]-has[l-1]*pw[r-l+1]?1:0;
}
struct Segment_Tree{
	#define leftson(p) p<<1
	#define rightson(p) p<<1|1
	#define push_up(p) tree[p].val=max(tree[leftson(p)].val,tree[rightson(p)].val)
	struct TREE{
		int l,r,val,tag;
	}tree[MAXN<<2];
	void build(int l,int r,int p){
		tree[p].l=l,tree[p].r=r;
		if(l==r)return;
		int mid=l+r>>1;
		build(l,mid,leftson(p));
		build(mid+1,r,rightson(p));
	}
	void spread(int p){
		if(tree[p].tag){
			tree[leftson(p)].val=max(tree[leftson(p)].val,tree[p].tag);
			tree[rightson(p)].val=max(tree[rightson(p)].val,tree[p].tag);
			tree[leftson(p)].tag=tree[p].tag;
			tree[rightson(p)].tag=tree[p].tag;
			tree[p].tag=0;
		}
	}
	void update(int l,int r,int k,int p){
		if(tree[p].l>=l&&tree[p].r<=r){
			tree[p].val=max(tree[p].val,k);
			tree[p].tag=k;
			return;
		}
		spread(p);
		int mid=tree[p].l+tree[p].r>>1;
		if(l<=mid)update(l,r,k,leftson(p));
		if(r>mid)update(l,r,k,rightson(p));
		push_up(p);
	}
	int query(int x,int p){
		if(tree[p].l==tree[p].r)return tree[p].val;
		spread(p);
		int mid=tree[p].l+tree[p].r>>1;
		if(x<=mid)return query(x,leftson(p));
		else return query(x,rightson(p));
	}
}ST;
signed main(){
	pw[0]=1;
	for(int i=1;i<MAXN;i++)pw[i]=pw[i-1]*p;
	scanf("%lld",&n);
	scanf("%s",txt+1);lt=strlen(txt+1);
	for(int i=1;i<=lt;i++)has[i]=has[i-1]*p+txt[i];
	ST.build(1,lt,1);
	for(int i=1;i<lt;i++){
		int l=i+1,r=min(2*i,lt);
		int qans=0;
		while(r>=l){
			int mid=l+r>>1;
			if(check(i+1,mid))qans=mid,l=mid+1;
			else r=mid-1;
		}
		if(qans)ST.update(i+1,qans,i,1)/*,printf("l:%d Qans:%d\n",l,qans)*/;
	}
	for(int i=2;i<=lt;i++)ans+=ST.query(i,1);
//	for(int i=1;i<=n<<2;i++)printf("p:%d l:%d r:%d val:%d\n",i,ST.tree[i].l,ST.tree[i].r,ST.tree[i].val);
	printf("%lld",ans);
	return 0;
}
#include<bits/stdc++.h>
#define ull unsigned long long//动物园
#define MAXN 1000005//Hash&Binary&diff
#define int long long
using namespace std;
int T,lt,ans;
const int p=131;
const int mod=1e9+7;
ull pw[MAXN],has[MAXN];
char txt[MAXN];
bool check(int l,int r){
	if(r-l+1>=l)return 0;
	return has[r-l+1]==has[r]-has[l-1]*pw[r-l+1];
}
int d[MAXN],sumd[MAXN];
signed main(){
	pw[0]=1;
	for(int i=1;i<MAXN;i++)pw[i]=pw[i-1]*p;
	scanf("%lld",&T);
	while(T--){
		ans=1;
		memset(d,0,sizeof(d));
		scanf("%s",txt+1);lt=strlen(txt+1);
		for(int i=1;i<=lt;i++)has[i]=has[i-1]*p+txt[i];
		for(int i=1;i<=lt;i++){
			int l=i,r=lt,qans=0;
			while(r>=l){
				int mid=l+r>>1;
				if(check(i,mid))qans=mid,l=mid+1;
				else r=mid-1;
			}
			if(qans)d[i]++,d[qans+1]--;
		}
		for(int i=1;i<=lt;i++)sumd[i]=d[i]+sumd[i-1];
		for(int i=1;i<=lt;i++)ans=((ans)*(sumd[i]+1))%mod;
		printf("%lld\n",ans);
	}
	return 0;
}
posted @ 2024-02-20 19:31  RVm1eL_o6II  阅读(2)  评论(0编辑  收藏  举报