Live2D

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

posted @ 2020-09-01 23:09  Wuzhouming  阅读(216)  评论(0编辑  收藏  举报