• bzoj 3796 Mushroom追妹纸 —— 后缀数组


    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3796

    先把三个串拼在一起,KMP 求 s1 , s2 中每个位置和 s3 的匹配情况;

    注意拼三个串时加入的两个新字符不要一样,否则会影响;

    然后预处理出每个位置后面的第一个 s3 的开头 —— 如果预处理结尾还得考虑它就在 s3 中的情况,易错...

    然后正反做 s2 对 s1 的贡献,在 s1 处考虑不包含 s3 即可,反正 s1 和 s2 求了 LCP,是一样的;

    还是得写得简洁优美,否则易错...

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int const xn=1e5+1e4+5,xm=1e4+5;
    int n,m,tax[xn],tp[xn],sa[xn],rk[xn],ht[xn][20],bin[20],bit[xn];
    int l1,l2,l3,nxt[xn],f[xn],g[xn];
    char a[xn],b[xn],s[xn],c[xm];
    void getnxt()
    {
      for(int i=2;i<=n;i++)
        {
          int nw=nxt[i-1];
          while(s[nw+1]!=s[i]&&nw)nw=nxt[nw];
          if(s[nw+1]==s[i])nw++;
          nxt[i]=nw;
          if(nw>=l3)g[i-l3+1]=1;//i:start
        }
      for(int i=n+1,lst=n+1;i;i--)
        {
          if(g[i])lst=i;
          f[i]=lst;
        }
    }
    void Rsort()
    {
      for(int i=1;i<=m;i++)tax[i]=0;
      for(int i=1;i<=n;i++)tax[rk[tp[i]]]++;
      for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
      for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void work()
    {
      for(int i=1;i<=n;i++)rk[i]=s[i],tp[i]=i;
      Rsort();
      for(int k=1;k<=n;k<<=1)
        {
          int num=0;
          for(int i=n-k+1;i<=n;i++)tp[++num]=i;
          for(int i=1;i<=n;i++)
        if(sa[i]>k)tp[++num]=sa[i]-k;
          Rsort(); swap(rk,tp);
          rk[sa[1]]=1; num=1;
          for(int i=2;i<=n;i++)
        rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?num:++num;
          if(num==n)break;
          m=num;
        }
    }
    void get()
    {
      int k=0;
      for(int i=1;i<=n;i++)
        {
          if(rk[i]==1)continue;
          if(k)k--; int j=sa[rk[i]-1];
          while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
          ht[rk[i]][0]=k;
        }
      bin[0]=1; for(int i=1;i<20;i++)bin[i]=(bin[i-1]<<1);
      bit[1]=0; for(int i=2;i<=n;i++)bit[i]=bit[i>>1]+1;
      for(int j=1;j<20;j++)
        for(int i=1;i<=n&&i+bin[j]-1<=n;i++)
          ht[i][j]=min(ht[i][j-1],ht[i+bin[j-1]][j-1]);
    }
    int getlcp(int x,int y)
    {
      if(x==y)return n-x+1;
      x=rk[x]; y=rk[y];
      if(x>y)swap(x,y); x++;
      int w=bit[y-x+1];
      return min(ht[x][w],ht[y-bin[w]+1][w]);
    }
    int main()
    {
      scanf("%s",a+1); l1=strlen(a+1);
      scanf("%s",b+1); l2=strlen(b+1);
      scanf("%s",c+1); l3=strlen(c+1);
      n=l1+l2+l3+2;
      for(int i=1;i<=l3;i++)s[i]=c[i]; s[l3+1]='a'-1;
      for(int i=1;i<=l1;i++)s[l3+1+i]=a[i]; s[l3+l1+2]='a'-2;//different
      for(int i=1;i<=l2;i++)s[l3+l1+2+i]=b[i];
      getnxt(); 
      n=l1+1+l2; m=125;
      for(int i=1;i<=l1;i++)s[i]=a[i]; s[l1+1]='a'-1;
      for(int i=1;i<=l2;i++)s[l1+1+i]=b[i];
      for(int i=1;i<=n;i++)
        {
          f[i]=f[i+l3+1]-l3-1;/*
          if(f[i]-l3+1<i)f[i]=f[i+l3+2]-l3-1;//!!
          if(f[i]==n+1)f[i]=n+1;//same 
          else f[i]=f[i]-i;*/
        }
      work(); get(); 
      int ans=0;
      for(int i=1,tmp=0;i<=n;i++)
        {
          int k=f[sa[i]]+l3-1-sa[i];
          if(sa[i]<=l1)
        {
          ans=max(ans,min(tmp,k));
          tmp=min(tmp,ht[i+1][0]);//+1
        }
          else if(sa[i]>l1+1)//
          tmp=ht[i+1][0];//
        }
      for(int i=n,tmp=0;i;i--)
        {
          int k=f[sa[i]]+l3-1-sa[i];
          if(sa[i]<=l1)
        {
          ans=max(ans,min(tmp,k));
          tmp=min(tmp,ht[i][0]);
        }
          else if(sa[i]>l1+1)//
          tmp=ht[i][0];
        }
      printf("%d
    ",ans);
      return 0;
    }
  • 相关阅读:
    求正整数N(N>1)的质因数的个数。
    手机键盘输入字母
    第二部分进度
    第一部分:地域维度标准化
    利用python解析地址经纬度
    输入任意4个字符(如:abcd), 并按反序输出(如:dcba)
    python-->微信支付
    python-图片流传输(url转换二维码)
    python-qrcode-二维码
    ajax和axios、fetch的区别
  • 原文地址:https://www.cnblogs.com/Zinn/p/10086147.html
Copyright © 2020-2023  润新知