码题集OJ-好像相等 (matiji.net)
思路:对26个字母单独哈希26*1e5,然后单独判断每个字母的哈希值是否相同即可。
const unsigned int base=131;
unsigned int p[100005],h[26][100005];
unsigned int n,k;
string str;
void hashInit(){
p[0]=1;
for(int i=0;i<26;i++){
for(int j=1;j<=n;j++){
p[j]=p[j-1]*base;
if(str[j]-'a'==i) h[i][j]=h[i][j-1]*base+str[j];
else h[i][j]=h[i][j-1]*base;
}
}
}
BD202419好像相等
https://www.matiji.net/exam/brushquestion/19/4498/F16DA07A4D99E21DFFEF46BD18FF68AD
void solve(){
cin>>n>>k;
cin>>str;
str=" "+str;
hashInit();
while(k--){
vector<char> vct;
int l1,r1,l2,r2; cin>>l1>>r1>>l2>>r2;
for(int i=0;i<26;i++){
if(h[i][r1]-h[i][l1-1]*p[r1-l1+1]!=h[i][r2]-h[i][l2-1]*p[r2-l2+1]) vct.emplace_back('a'+i);
}
cout<<vct.size()<<endl;
for(auto v:vct) cout<<v;
cout<<endl;
}
}
E-“好”字符_河南萌新联赛2024第(二)场:南阳理工学院 (nowcoder.com)
思路:同样是单独哈希26个字母。这里因为这里字母可以循环移动,比上一题麻烦一点点,推一下式子计算一下哈希值即可。
const unsigned int base=131;
//const int mod=998244357;
unsigned int p[1000006],h[26][1000006];
unsigned int ha[26],existA[26],existB[26]; 用map会导致MLE!!
unordered_map<int,bool> mark;
unsigned int n;
string a,b;
void hashInit(){ 用unsigned long long 就不用考虑取mod!! 不然取mod取错就寄
p[0]=1;
for(int i=0;i<26;i++){
int h0=0;
for(int j=1;j<=n;j++){
p[j]=p[j-1]*base;
if(b[j]-'a'==i) h[i][j]=(h[i][j-1]*base+b[j]),existB[i]=1;
else h[i][j]=(h[i][j-1]*base);
if(a[j]-'a'==i) h0=(h0*base+a[j]),existA[i]=1;
else h0=(h0*base);
}
ha[i]=h0;
mark[h0]=1;
}
}
“好”字符
https://ac.nowcoder.com/acm/contest/87255/E
void solve(){ 补E 字符串哈希
cin>>n>>a>>b;
a=" "+a,b=" "+b;
hashInit();
int ans=0;
for(int c=0;c<26;c++){
if(!existA[c]||!existB[c]) continue;
for(int i=0;i<n;i++){
if(ha[c]==((h[c][n]-h[c][i]*p[n-i])*p[i]+h[c][i])){
ans++;
break;
}
}
}
cout<<ans;
}
Fixing a Binary String - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
思路:这题因为操作会使字符串翻转,那么可以直接把原始字符串顺/逆都哈希一次,然后计算哈希值即可。切记减的时候不要忘记补上差的base..警钟长鸣!
单哈希:
自然溢出
const ull base=131;
ull p[200005],h[2][200005],h0=0,h1=0; 输入的字符串顺逆都哈希一次
int n,k;
string str,ReStr;
void hashInit(){
string str0=" ",str1=" ";
int cnt=0,mark=1;
p[0]=1,h[0][0]=0,h[1][0]=0;
for(int i=1;i<=n;i++){
p[i]=p[i-1]*base;
h[0][i]=h[0][i-1]*base+str[i];
h[1][i]=h[1][i-1]*base+ReStr[i];
if(mark) str0+="0",str1+="1";
else str0+="1",str1+="0";
cnt++;
if(cnt>=k) cnt=0,mark^=1;
}
for(int i=1;i<=n;i++){
h0=h0*base+str0[i];
h1=h1*base+str1[i];
}
}
D. Fixing a Binary String
https://www.luogu.com.cn/problem/CF1979D
void solve(){ 字符串哈希---------单哈希(自然溢出)
cin>>n>>k;
cin>>str;
ReStr=str,reverse(ReStr.begin(),ReStr.end()),ReStr=" "+ReStr;
str=" "+str;
h0=0,h1=0; 初始化
hashInit();
for(int i=1;i<=n;i++){
ull cur=(h[0][n]-h[0][i]*p[n-i])*p[i]+h[1][n]-h[1][n-i]*p[i]; 两个减都少了base
if(cur==h0||cur==h1){
cout<<i<<endl;
return;
}
}
cout<<"-1"<<endl;
}
双哈希(双倍空间):
const ull base=131;
const int baseb=13331;
const int mod=998244353;
ull p[200005],h[2][200005],h0=0,h1=0;
int pp[200005],hh[2][200005],hh0=0,hh1=0;
int n,k;
string str,ReStr;
void hashInit(){
string str0=" ",str1=" ";
int cnt=0,mark=1;
p[0]=1,pp[0]=1;
for(int i=1;i<=n;i++){
p[i]=p[i-1]*base;
h[0][i]=h[0][i-1]*base+str[i];
h[1][i]=h[1][i-1]*base+ReStr[i];
pp[i]=pp[i-1]*baseb,pp[i]%=mod;
hh[0][i]=hh[0][i-1]*baseb+str[i],hh[0][i]%=mod;
hh[1][i]=hh[1][i-1]*baseb+ReStr[i],hh[1][i]%=mod;
if(mark) str0+="0",str1+="1";
else str0+="1",str1+="0";
cnt++;
if(cnt>=k) cnt=0,mark^=1;
}
for(int i=1;i<=n;i++){
h0=h0*base+str0[i];
h1=h1*base+str1[i];
hh0=hh0*baseb+str0[i],hh0%=mod;
hh1=hh1*baseb+str1[i],hh1%=mod;
}
}
D. Fixing a Binary String
https://www.luogu.com.cn/problem/CF1979D
void solve(){ 字符串哈希--------------双哈希(自然溢出+mod)
cin>>n>>k;
cin>>str;
ReStr=str,reverse(ReStr.begin(),ReStr.end()),ReStr=" "+ReStr;
str=" "+str;
h0=0,h1=0,hh0=0,hh1=0; 初始化
hashInit();
for(int i=1;i<=n;i++){
pair<ull,int> cur;
cur.first=(h[0][n]-h[0][i]*p[n-i])*p[i]+h[1][n]-h[1][n-i]*p[i];
cur.second=((hh[0][n]-hh[0][i]*pp[n-i]%mod+mod)%mod*pp[i]%mod+(hh[1][n]-hh[1][n-i]*pp[i]%mod+mod)%mod)%mod;
if(cur==make_pair(h0,hh0)||cur==make_pair(h1,hh1)){
cout<<i<<endl;
return;
}
}
cout<<"-1"<<endl;
}
Problem - 7433 (hdu.edu.cn)循环位移
思路:哈希典题,找子串。unordered_map标记stra的k个哈希值。
const ull base=131;
string stra,strb;
ull ha[1050000],hb[1050000];
ull p[1050000];
int na,nb;
void hashInit(){
p[0]=1;
for(int i=1;i<=nb;i++){
if(i<=na) ha[i]=ha[i-1]*base+stra[i];
p[i]=p[i-1]*base;
hb[i]=hb[i-1]*base+strb[i];
}
}
如果枚举k,遍历strb时间复杂度为na*(nb-na)--TLE
优化,标记stra的k个哈希值,o(nb)遍历strb--ac
循环位移
https://acm.hdu.edu.cn/showproblem.php?pid=7433
和牛客萌新赛的,"好"字符,非常相似
void solve(){
cin>>stra>>strb;
na=stra.size(),nb=strb.size();
stra=" "+stra,strb=" "+strb;
hashInit();
ull cnt=0;
unordered_map<ull,bool> mark;
for(int k=0;k<na;k++){
ull cura=(ha[na]-ha[k]*p[na-k])*p[k]+ha[k];
mark[cura]=1;
}
for(int i=na;i<=nb;i++){
ull curb=hb[i]-hb[i-na]*p[na];
if(mark[curb]) cnt++;
}
cout<<cnt<<endl;
}