字符串hash
目的:把字符串有效地转化为一个整数,极小的概率会出现两个字符串hash值相等。
学习链接:https://www.luogu.org/blog/pks-LOVING/zi-fu-chuan-xue-xi-bi-ji-ha-xi-hash-yu-zi-dian-shu-trie#
hash[i]=(hash[i-1]*p+idx(s[i]))%mod
hash[l..r]=(hash[r]-hash[l-1]*(p^(r-l+1))+mod)%mod
自动取模hash:unsigned long long hash[maxn],范围[0, 2^64) ,即mod=2^64
保险double hash,mod1=1e9+7,mod2=1e9+9,mod1与mod2为孪生素数,冲突概率极低(hash的维度越高,耗时越高,耗内存越大)
hash1[i]=(hash1[i-1]*p+idx(s[i]))%mod1
hash2[i]=(hash2[i-1]*p+idx(s[i]))%mod2
基本操作:二分+hash
自用模板:
P3370 【模板】字符串哈希:https://www.luogu.org/problemnew/show/P3370
#include<bits/stdc++.h> using namespace std; #define ull unsigned long long const int maxn=1e4+10; ull base=131,mod=21237044013013795711; int prime=233317; ull hashe(char *s) { int len=strlen(s); ull ans=0; for(int i=0;i<len;i++) { ans=(ans*base+(ull)s[i])%mod+prime; } return ans; } int main() { int n,ans=1; char s[maxn]; ull a[maxn]={0}; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s",s); a[i]=hashe(s); } sort(a+1,a+n+1); for(int i=1;i<n;i++) { if(a[i]!=a[i+1])ans++; } printf("%d\n",ans); return 0; }
P2957谷仓里的回声Barn Echoes:https://www.luogu.org/problemnew/show/P2957,前缀后缀最长公共部分,kmp可做
#include<bits/stdc++.h> #define ull unsigned long long using namespace std; const int maxn=100; ull base=131,mod=21237044013013795711; int prime=233317; ull hashe(string s) { int len=s.size(); ull ans=0; for(int i=0;i<len;i++) { ans=(ans*base+(ull)s[i])%mod+prime; } return ans; } string s,s2; ull a[maxn],a2[maxn]; int main() { int ans=0,len; cin>>s>>s2; len=min(s.size(),s2.size()); for(int i=1;i<=len;i++) { string tmp1=s.substr(s.size()-i,i),tmp2=s2.substr(0,i); if(hashe(tmp1)==hashe(tmp2)&&i>ans)ans=i; } for(int i=1;i<=len;i++) { string tmp1=s2.substr(s2.size()-i,i),tmp2=s.substr(0,i); if(hashe(tmp1)==hashe(tmp2)&&i>ans)ans=i; } printf("%d\n",ans); return 0; }
P1381单词背诵:https://www.luogu.org/problem/P1381,n个单词要背,m个单词序列,选一段序列使得包含要背诵的单词num越多越好,num相等时序列长度len越短越好,输出num和len。单词用hashe处理,方法为O(n)复杂度的尺取,刚开始wa在越多越好这个点,其实这个数num是可算的,m个单词里滚一边出现过几种要背的单词就好了。可能没出现过,这种情况放到while里不能跳出循环,因为sum和num始终为0,所以需要特判。
#include<bits/stdc++.h> #define INF 0x3f3f3f3f #define ull unsigned long long using namespace std; const int maxn=1e5+10; ull base=131,mod=21237044013013795711; int prime=233317; ull hashe(char *s) { int len=strlen(s); ull ans=0; for(int i=0;i<len;i++) { ans=(ans*base+(ull)s[i])%mod+prime; } return ans; } map<ull,int> appear,mp,vis; ull cnt[maxn]; int main() { int n,m,num=0; scanf("%d",&n); for(int i=0;i<n;i++) { char s[20]; scanf("%s",s); ull tmp=hashe(s); appear[tmp]=1; } scanf("%d",&m); for(int i=0;i<m;i++) { char s[20]; scanf("%s",s); ull tmp=hashe(s); cnt[i]=hashe(s); if(appear[tmp]==1&&!vis[tmp])num++,vis[tmp]=1; } if(num==0){printf("0\n0\n");return 0;} int st=0,en=0,sum=0,len=INF; while(1) { while(en<m&&sum<num) { if(mp[cnt[en]]==0&&appear[cnt[en]]==1)sum++; mp[cnt[en]]++; en++; } if(sum==num)len=min(len,en-st); if(sum<num)break; mp[cnt[st]]--; if(mp[cnt[st]]==0&&appear[cnt[st]]==1)sum--; st++; } printf("%d\n%d\n",num,len); return 0; }
...