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))位
接着,分情况讨论:

  1. (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;
  }
  1. (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

原文地址:https://www.cnblogs.com/Wuzhuoming-sirenboke/p/13599336.html