hash

hash

base 是个进制,一般都要用素数(逆元方便)——越大越好 例如131,1E9+7,1E9+9,232,264,23333333333333

模板

单哈希

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const ull mod=212370440130137957ll;
ull base=131,a[10010];
int n,sum=1;
char s[10010];
ull hash(char *s){
    int len=strlen(s);
    ull ans=0;
    for(int i=0;i<len;i++)
        ans=(ans*base+(ull)s[i])%mod;
    return ans;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        a[i]=hash(s);
    }
    sort(a+1,a+1+n);
    for(int i=2;i<=n;i++)
        if(a[i]!=a[i-1])
            sum++;
    printf("%d\n",sum);
    return 0;
}

双哈希

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const ull mod1=19260817;
const ull mod2=19660813;
struct data{
    ull x,y;
}a[10010];
ull base=131;
int n,sum=1;
char s[10010];
ull hash1(char *s){
    int len=strlen(s);
    ull ans=0;
    for(int i=0;i<len;i++)
        ans=(ans*base+(ull)s[i])%mod1;
    return ans;
}
ull hash2(char *s){
    int len=strlen(s);
    ull ans=0;
    for(int i=0;i<len;i++)
        ans=(ans*base+(ull)s[i])%mod2;
    return ans;
}
bool cmp(data a,data b){
    return a.x<b.x;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        a[i].x=hash1(s);
        a[i].y=hash2(s);
    }
    sort(a+1,a+1+n,cmp);
    for(int i=2;i<=n;i++)
        if(a[i].x!=a[i-1].x || a[i].y!=a[i-1].y)
            sum++;
    printf("%d\n",sum);
    return 0;
}

例1:「LibreOJ NOIP Round #1」DNA 序列

很水的题,搞个map 和hash前缀和即可

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const int base=131;
const int N=5e6+10;
char s[N];
int k;
ull has[N],ak;
map<ull,int>cnt;
int mx=0;
int main(){
    scanf("%s",s+1);
    scanf("%d",&k);
    int len=strlen(s+1);
    ak=1;
    for(int i=1;i<=k;i++)
        ak=ak*base;
    has[0]=0;
    for(int i=1;i<=len;i++)
        has[i]=has[i-1]*base+s[i];
    for(int i=1;i<=len-k+1;i++)
        mx=max(mx,++cnt[has[i+k-1]-has[i-1]*ak]);
    printf("%d\n",mx);
    return 0;
}

例2:企鹅QQ

枚举哪一位不同,hash 除了 i 这一位的前缀和后缀

然后sort比较即可

#include <iostream>
#include <cstdio>
#include <algorithm>
const int N=3e4+5;
const int M=205;
using namespace std;
typedef unsigned long long ull;
inline int read(){
	int x=0;char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
	return x;
}
int n,l,s,sum,ans;
char ch[M];
ull hs[N],hs1[N][M],hs2[N][M];
int base1=131,base2=137;
void init(int x){
	for(int i=1;i<=l;i++)
		hs1[x][i]=hs1[x][i-1]*base1+ch[i];
	for(int i=l;i>=1;i--)
		hs2[x][i]=hs2[x][i+1]*base2+ch[i];
}
int main(){
	n=read();l=read();s=read();
	for(int i=1;i<=n;i++){
		scanf("%s",ch+1);
		init(i);
	}
	for(int i=1;i<=l;i++){//枚举哪一位不同
		sum=1;
		for(int j=1;j<=n;j++)
			hs[j]=hs1[j][i-1]*233+hs2[j][i+1]*211;
		sort(hs+1,hs+1+n);
		for(int j=2;j<=n;j++)
			if(hs[j]==hs[j-1])
				ans+=sum,sum++;
			else sum=1;
	}
	printf("%d",ans);
	return 0;
} 

例3:Stammering Aliens

Description

在一个字符串中求出现次数大于等于n的最长子串

Solution

二分子串长度,hash 然后存进map 里

#include <cstdio>
#include <iostream>
#include <map>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const ull mod=19260817;
ull base=131,a[40010];
int n,len,ans=-1;
char s[40010];
ull has[40010];
bool check(int x){
    map<int,int>mp;
    ull res;
    for(int i=1;i+x-1<=len;i++){
        res=has[i+x-1]-has[i-1]*a[x];
        if(++mp[res]>=n) return 1;
    }
    return 0;
}
int get(int x){
    map<int,int>mp;
    ull res;
    int pos=-1;
    for(int i=1;i+x-1<=len;i++){
        res=has[i+x-1]-has[i-1]*a[x];
        if(++mp[res]>=n) pos=i;
    }
    return pos-1;
}
int main(){
    while(~scanf("%d",&n)){
        if(!n) return 0;
        scanf("%s",s+1);
        len=strlen(s+1);
        has[0]=0;a[0]=1;
        for(int i=1;i<=len;i++){
            has[i]=has[i-1]*base+s[i];
            a[i]=a[i-1]*base;
        }
        int l=1,r=len+1;
        ans=-1;
        //二分长度
        while(l<=r){
            int mid=(l+r)>>1;
            if(check(mid)) ans=mid,l=mid+1;
            else r=mid-1;
        }
        if(ans<=-1) puts("none");
        else printf("%d %d\n",ans,get(ans));
    }
}

例4:Hash Killer I

神奇构造题

https://www.cnblogs.com/sahdsg/p/10849807.html

例5:二维哈希

比较像二维前缀和

#include <iostream>
#include <cstdio>
#include <map>
#include <cstring>
using namespace std;
typedef unsigned long long ull;
const int base1=131;
const int base2=233;
const int N=1005;
char s[N],c[105][105];
int n,m,a,b,q;
ull has[N][N],ak1=1,ak2=1;
map<ull,int>cnt;
int mx=0;
int main(){
    scanf("%d%d%d%d",&n,&m,&a,&b);
    for(int i=1;i<=n;i++){
        scanf("%s",s+1);
        for(int j=1;j<=m;j++)
            has[i][j]=has[i][j-1]*base1+s[j];
    }
    for(int i=1;i<=n;i++)   
        for(int j=1;j<=m;j++)
            has[i][j]+=has[i-1][j]*base2;
    for(int i=1;i<=b;i++) ak1=ak1*base1;
    for(int i=1;i<=a;i++) ak2=ak2*base2;
    for(int i=a;i<=n;i++)
        for(int j=b;j<=m;j++)
            cnt[has[i][j]-ak2*has[i-a][j]-ak1*has[i][j-b]+has[i-a][j-b]*ak1*ak2]=1;
    scanf("%d",&q);
    while(q--){
        ull res=0,ans=0;
        for(int i=1;i<=a;res=0,i++){
            scanf("%s",c[i]+1);
            for(int j=1;j<=b;j++)
                res=res*base1+c[i][j];
            ans=ans*base2+res;
        }
        if(cnt.count(ans)) printf("1\n");
        else printf("0\n");
    }
    return 0;
}

哈希表

例题:

不重复数字

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const int N=5e5+15;
const int P=100003;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
struct HASH{
	int nxt[N],hd[P+100],val[N],tot,to[N];
	inline void ins(int v) {
		int x=(v%P+P)%P;
		for(int i=hd[x];i;i=nxt[i]) {
			if(to[i]==v) {
				++val[i];return;
			}
		}
		to[++tot]=v;val[tot]=1;nxt[tot]=hd[x];hd[x]=tot;
	}
	inline int query(int v) {
		int x=(v%P+P)%P;
		for(int i=hd[x];i;i=nxt[i]) 
			if(to[i]==v) return val[i];
		return 0;
	}
	inline void clear() {
//		for(int i=0;i<=tot;i++) hd[i]=0;
		memset(hd,0,sizeof(hd));
		tot=0;
	}
}H;
int n,a[N];
int main() {
	int T=read();
	while(T--) {
		H.clear();
		n=read();
		for(int i=1;i<=n;i++) {
			a[i]=read();
			if(H.query(a[i])) continue;
			H.ins(a[i]);
			printf("%d ",a[i]);
		}
		puts("");
	}
	return 0;
}

CF776C Molly's Chemicals

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;
typedef long long ll;
const int N=1e5+10;
const ll inf=1e15;
const int P = 100003;
inline int read() {
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f*x;
}
int n,k;
ll a[N],mi[65];
struct HashTable {
	int nxt[N],val[N],hd[N],tot;
	ll to[N];//hash 
	inline void ins(ll v) {
		int x=v%P;
		if(x<0) x+=P;
		for(int i=hd[x];i;i=nxt[i]) {
			ll y=to[i];
			if(y==v) {++val[i];return;}
		}
		to[++tot]=v;val[tot]=1;nxt[tot]=hd[x];hd[x]=tot;
	}
	inline int query(ll v) {
		int x=v%P;
		if(x<0) x+=P;
		for(int i=hd[x];i;i=nxt[i]) {
			ll y=to[i];
			if(y==v) return val[i];
		}
		return 0;
	}
	inline void clear() {
		memset(hd,0,sizeof(hd));
		tot=0;
	}
}H;
int main() {
	H.clear();
	n=read();k=read();
	int len=0;
	if(k==1) {
		mi[0]=1;len=1;
	} else if(k==-1) {
		mi[0]=1;mi[1]=-1;
		len=2;
	} else {
		ll x=1;
		while(-inf<=x&&x<=inf) 
			mi[len++]=x,x*=k;
	}
	H.ins(0);
	ll ans=0,sum=0;
	for(int i=1;i<=n;i++) {
		int x=read();sum+=x;
		for(int j=0;j<len;j++) 
			ans+=H.query(sum-mi[j]);
		H.ins(sum);
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2020-11-03 09:15  ke_xin  阅读(14)  评论(0编辑  收藏  举报