luogu:hash专题题解
T1 :
运用hash,将每一个字符串储存到\(a_1\)~\(a_n\)这个数组中
ll ans=0,len=strlen(chr);
for(int i=0;i<len;i++)
ans=(ans*base+(ll)chr[i])%mod;
return ans;
然后对\(a\)排下序
判断:若后一个和前一个不同的话,记数
题目链接:洛谷P3370【模板】字符串哈希
T2 :
这题可以使用map进行操作
\(vi[]\)代表使用过了,\(vis[]\)代表出现过,使用\(num\)进行记数
if(vis[s] && !vi[s]) {
vi[s]=1;
num++;
}
\(num\)求出来就是文章中最多包含的要背的单词数
\(v[]\)代表这个单词出现次数
if(!v[s]) cnt++;//以前没出现cnt++
v[s]++;//出现次数++
while(!vis[a[head]] || (head<i && v[a[head]]>1)) {//不用背或者出现了>1次
v[a[head]]--;
head++;
}
if(cnt==num) ans=min(ans,i-head+1);
最后输出\(ans\)即可
题目链接:P1381 单词背诵
T3 :
若n为偶数,直接输出“NOT POSSIBLE”
然后\(n/=2\)
先将前(\(n/2-1\))位读入,然后再读入后(\(n/2\))位
接着,分情况讨论:
- 若\(a[0]!=b[0]\),\(ans\)这个字符串取后半段
对前半段和\(ans\)进行比对,如果有\(>=2\)个字符对应不上即可输出“NOT POSSIBLE”
代码片段如下:
for(int i=0,tot=0; i<=n && tot<n; i++)
if (str[i]==ans[tot])
tot++;
if (tot!=n) {
printf("NOT POSSIBLE");
return 0;
}
- 若\(a[0]==b[0]\),\(ans\)这个字符串取前半段
对后半段和\(ans\)进行比对,如果有\(>=2\)个字符对应不上即可输出“NOT POSSIBLE”
原理同上,不再多写
再者,前面已经证明有解了,现在再看看前后两段是否对的上,如果对不上,说明有2个及以上的解,输出“NOT UNIQUE"
if(str[0] == str[n] && str[0] == str[2 * n]) {
for(int i = 1; i <= 2 * n; i++)
if(str[i] != str[i - 1]) {
printf("NOT UNIQUE");
return 0;
}
}
最后,全部都检查完毕,可以直接输出ans这个字符串
题目链接:LOJ #2823. 「BalticOI 2014 Day 1」三个朋友
T4:
STL大法好
好吧,我用了\(<cstring>\)库中的\(substr\),
用处是复制子字符串,要求从指定位置开始,并具有指定的长度
核心代码如下:
for(int i=0; i<=DNA.length()-k; i++) {
int h=Hash(DNA.substr(i, k));
m[h]++;
ans=max(ans,m[h]);
}
题目链接:LOJ #537.「LibreOJ NOIP Round #1」DNA序列
T5:
枚举每一个状态,找到了就打上\(flag\)
子函数:
ll get_hash(int l,int r) {
return (h[r]-h[l-1]*pw[r-l+1])%mod;
}//要用到课上讲的get_hash
void work(ll* f,int* fl,int* k,int* l,int *r)
{
if(*f==0) *f=get_hash(*l,*r);
else if(*f!=get_hash(*l,*r)) {
*k=1;
*fl=1;
}
}
我们定义\(h0,h1\)为'0','1'代表的子串的hash值,p为'1'子串的长度,\(l,r\)为当前位置,\(fl\)为当前循环过程是否失败。
然后直接枚举所以可能值
核心判断部分 :
for(int j=0;j<lena;j++) {
int k=0;
l=r+1;
if(a[j]=='0'){
r+=i;
work(&h0,&fl,&k,&l,&r);
if(k) break;
}
if(a[j]=='1'){
r+=p;
work(&h1,&fl,&k,&l,&r);
if(k) break;
}
}
判断a,b是否是相同的串,并更新答案:
最后输出
if(h0==h1) continue;//若0,1的hash值相等,直接continue
if(!fl) ans++;
题目链接:洛谷CF1056E Check Transcription
T6 :
看了看数据范围:$\ n<=50 $
可以暴力
核心部分 :
if(a[i1][j1]==b[i2][j2])
f[i1][j1][i2][j2]=min(f[i1-1][j1-1][i2-1][j2-1],min(f[i1][j1-1][i2][j2-1],f[i1-1][j1][i2-1][j2]))+1;
ans=max(ans,f[i1][j1][i2][j2]);
复杂度O(\(n^4\))
dp+暴力 轻松水过
题目链接:洛谷P4398 [JSOI2008]Blue Mary的战役地图
T7:
dp,然而并不需要hash
\(f[i][j]\)表示分别以\(a[i],b[j]\)结尾的最长的相同部分的子串的长度。
\(n^2\)地枚举i,j,若\(a[i]=b[j],f[i][j]=f[i-1][j-1]+1\),否则,\(f[i][j]=f[i-1][j-1]\)。
从i=1开始计数,否则会有负质数
题目链接:洛谷P2957 [USACO09OCT]Barn Echoes G