zoukankan      html  css  js  c++  java
  • BZOJ4340 : BJOI2015 隐身术

    枚举$B$串的每个后缀,统计出该后缀所有满足条件的前缀。

    考虑暴力搜索,设状态$(x,y,z)$表示当前需要考虑$A$从$x$开始的后缀,$B$从$y$开始的后缀,之前部分编辑距离为$z$。

    那么首先用后缀数组+ST表求出两个后缀的lcp,$x$和$y$都可以向右跳那么多,且不产生任何代价。

    如果此时匹配到了底,那么可以得到在一段区间$[L,R]$内,所有前缀都是合法的。注意到这种前缀只有$2K+1$种,所以可以使用差分前缀和来进行标记。

    如果还没有匹配到底,那么有$3$种选择,分别是状态$(x+1,y,z+1)$、$(x,y+1,z+1)$以及$(x+1,y+1,z+1)$。

    时间复杂度$O(nlog n+n3^k)$。

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define N 100010
    using namespace std;
    char s[N],A[N],B[N];
    int K,na,nb,n,m,i,j,rk[N],sa[N],height[N],tmp[N],cnt[N],Log[N],f[17][N],c[15],ans;
    void suffixarray(int n,int m){
      int i,j,k;n++;
      for(i=0;i<n;i++)cnt[rk[i]=s[i]]++;
      for(i=1;i<m;i++)cnt[i]+=cnt[i-1];
      for(i=0;i<n;i++)sa[--cnt[rk[i]]]=i;
      for(k=1;k<=n;k<<=1){
        for(i=0;i<n;i++){
          j=sa[i]-k;
          if(j<0)j+=n;
          tmp[cnt[rk[j]]++]=j;
        }
        sa[tmp[cnt[0]=0]]=j=0;
        for(i=1;i<n;i++){
          if(rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k])cnt[++j]=i;
          sa[tmp[i]]=j;
        }
        memcpy(rk,sa,n*sizeof(int));
        memcpy(sa,tmp,n*sizeof(int));
        if(j>=n-1)break;
      }
      for(j=rk[height[i=k=0]=0];i<n-1;i++,k++)
        while(~k&&s[i]!=s[sa[j-1]+k])height[j]=k--,j=rk[sa[j]+1];
    }
    inline int ask(int x,int y){
      int k=Log[y-x+1];
      return min(f[k][x],f[k][y-(1<<k)+1]);
    }
    inline int lcp(int x,int y){
      if(x>=na||y>=nb)return 0;
      x=rk[x],y=rk[y+na+1];
      if(x>y)swap(x,y);
      return ask(x+1,y);
    }
    inline void col(int l,int r){
      if(l<i)l=i;
      if(r>=nb)r=nb-1;
      c[l-i-na+K+2]++,c[r-i-na+K+3]--;
    }
    void dfs(int x,int y,int z){
      int t=lcp(x,y);
      x+=t,y+=t;
      if(x==na||y==nb){
        int c=K-(z+na-x);
        if(c>=0)col(y-1-c,y-1+c);
        return;
      }
      if(z==K)return;
      z++;
      dfs(x+1,y,z);
      dfs(x,y+1,z);
      dfs(x+1,y+1,z);
    }
    int main(){
      scanf("%d%s%s",&K,A,B);
      na=strlen(A),nb=strlen(B);
      for(i=0;i<na;i++)s[n++]=A[i];
      s[n++]='#';
      for(i=0;i<nb;i++)s[n++]=B[i];
      suffixarray(n,128);
      for(i=2;i<=n;i++)Log[i]=Log[i>>1]+1;
      for(i=1;i<=n;i++)f[0][i]=height[i];
      for(j=1;j<17;j++)for(i=1;i+(1<<j-1)<=n;i++)f[j][i]=min(f[j-1][i],f[j-1][i+(1<<j-1)]);
      for(m=2*K+1,i=0;i<nb;i++){
        for(j=1;j<=m;j++)c[j]=0;
        dfs(0,i,0);
        for(j=1;j<=m;j++)if(c[j]+=c[j-1])ans++;
      }
      return printf("%d",ans),0;
    }
    

      

  • 相关阅读:
    上传文件
    vue 动态数据请求
    Layui——layerjs 用法汇总(持续更新)
    以插入排序为例子带你彻底理解算法中的时间复杂度和各种渐进符号
    flappy pig小游戏源码分析(4)——核心pig模块(未完待续)
    flappy pig小游戏源码分析(3)——解剖util
    flappy pig小游戏源码分析(2)——解剖option
    flappy pig小游戏源码分析(1)——主程序初探
    Express细节探究(1)——app.use(express.static)
    部分常用Express方法详解
  • 原文地址:https://www.cnblogs.com/clrs97/p/5106772.html
Copyright © 2011-2022 走看看