zoukankan      html  css  js  c++  java
  • luogu P4770 [NOI2018]你的名字

    传送门

    upd 19.4.24:

    WC这个做法真的有问题,不往回跳会WA是因为一开始跳到了S[1...l-1]所对应的点,然后往后接字符的时候可能会因为不在正确的endpos中,然后往回跳过头,其实一开始只要从起点开始跳就行了

    Orz @Itst ddw


    这题写死我了,因为一点点鬼会注意到的细节调好久,,,

    先考虑前17个点,如果我们不考虑T的不同子串限制,那么就是把T放在S的SAM上匹配,答案为(sum_{i=1}^{|T|}i-l[i])(匹配长度).考虑怎么判重,对T也构建一个SAM,由于每个前缀的贡献答案的子串左端点在([1,i-l[i]))之间,对应到parent树上就是若干条链,那么每个位置的贡献就是对应链的没有被前面的链覆盖的部分

    后面的点,首先我们每次要跳到S[1...l-1]所对应的点,然后把T放在上面匹配,不过可能匹配过程中,S匹配上的子串没有在[l,r]之间的,这时候我们要跳parent,去掉匹配子串的前面一些部分,使得[l,r]之间出现对应的串.这个可以通过SAM每个节点开一棵线段树维护endpos集合,通过线段树合并维护,每次查询对应状态[l,r]中最大的结束位置-匹配长度+1是否(ge l)

    (这种做法有点问题,可能跳parent会因为串的前面部分而跳过头,导致匹配长度变小,从而导致答案变大,所以跳完后要尝试往回跳orz)

    // luogu-judger-enable-o2
    #include<bits/stdc++.h>
    #define LL long long
    #define il inline
    #define re register
    #define db double
    
    using namespace std;
    const int N=1000000+10;
    il LL rd()
    {
      LL x=0,w=1;char ch=0;
      while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
      while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();}
      return x*w;
    }
    char cc[N],ss[N];
    int n,m;
    int an[N>>1],bk[N>>1],aa[N],loc[N>>1],st[N],tp;
    int s[N*22],ch[N*22][2],rt[N],tot;
    il void inst(int o1,int o2,int x)
    {
      int l=1,r=n;
      s[o1]=max(s[o2],x);
      while(l<r)
        {
          int mid=(l+r)>>1;
          if(x<=mid)
            {
              ch[o1][0]=++tot,ch[o1][1]=ch[o2][1];
              o1=ch[o1][0],o2=ch[o2][0];
              r=mid;
            }
          else 
            {
              ch[o1][0]=ch[o2][0],ch[o1][1]=++tot;
              o1=ch[o1][1],o2=ch[o2][1];
              l=mid+1;
            }
          s[o1]=max(s[o2],x);
        }
    }
    int merge(int o1,int o2)
    {
      if(!o1||!o2) return o1+o2;
      //if(o1==o2) return o1;
      int o=++tot;
      s[o]=max(s[o1],s[o2]);
      ch[o][0]=merge(ch[o1][0],ch[o2][0]),ch[o][1]=merge(ch[o1][1],ch[o2][1]);
      return o;
    }
    int quer(int o,int l,int r,int ll,int rr)
    {
      if(!o) return s[0];
      if(ll<=l&&r<=rr) return s[o];
      int mid=(l+r)>>1,an=s[0];
      if(ll<=mid) an=/*max(an,*/quer(ch[o][0],l,mid,ll,rr)/*)*/;
      if(rr>mid) an=max(an,quer(ch[o][1],mid+1,r,ll,rr));
      return an;
    }
    struct SAM
    {
      int fa[N],len[N],a[N],la,tt;
      int ch[N][26];
      bool v[N];
      SAM(){la=tt=1;}
      il void inst(char c,int id)
      {
        int np=++tt,p=la;
        la=np,a[np]=id,len[np]=len[p]+1;
        while(p&&!ch[p][c-'a']) ch[p][c-'a']=np,p=fa[p];
        if(!p) fa[np]=1;
        else
          {
            int q=ch[p][c-'a'];
            if(len[q]==len[p]+1) fa[np]=q;
            else
              {
                int nq=++tt;
                fa[nq]=fa[q],len[nq]=len[p]+1,fa[q]=fa[np]=nq;
                for(int i=0;i<26;++i) ch[nq][i]=ch[q][i];
                while(p&&ch[p][c-'a']==q) ch[p][c-'a']=nq,p=fa[p];
              }
          }
      }
      il void clear()
      {
        memset(ch,0,4*26*(tt+2));
        memset(v,0,1*(tt+2));
        memset(fa,0,4*(tt+2));
        memset(len,0,4*(tt+2));
        la=tt=1;
      }
    }a,b;
    
    int main()
    {
      scanf("%s",ss+1);
      n=strlen(ss+1);
      for(int i=1;i<=n;++i) a.inst(ss[i],i);
      for(int i=1;i<=a.tt;++i) ++bk[a.len[i]];
      for(int i=1;i<=n;++i) bk[i]+=bk[i-1];
      for(int i=1;i<=a.tt;++i) aa[bk[a.len[i]]--]=i;
      memset(s,-63,sizeof(s));
      for(int i=a.tt,las;i;--i)
        {
          if(a.a[aa[i]]) las=rt[aa[i]],inst(rt[aa[i]]=++tot,las,a.a[aa[i]]);
          rt[a.fa[aa[i]]]=merge(rt[a.fa[aa[i]]],rt[aa[i]]);
        }
      loc[0]=1;
      for(int i=1,nw=1;i<=n;++i) loc[i]=nw=a.ch[nw][ss[i]-'a'];
      int q=rd();
      while(q--)
        {
          scanf("%s",cc+1);
          m=strlen(cc+1);
          LL ans=0;
          int l=rd(),r=rd();
          for(int i=1,nw=loc[l-1],kk=0;i<=m;++i)
            {
              int w=cc[i]-'a';
              while(nw&&!a.ch[nw][w]) nw=a.fa[nw],kk=a.len[nw];
              if(!nw) nw=1,kk=0;
              else nw=a.ch[nw][w],++kk;
              tp=0;
              while(nw&&quer(rt[nw],1,n,l,r)-kk+1<l)
                st[++tp]=nw,nw=a.fa[nw],kk=a.len[nw];
              if(tp)
                {
                  while(quer(rt[nw],1,n,l,r)-kk+1>=l) ++kk,nw=(kk<=a.len[nw])?nw:st[tp--];
                  --kk,nw=(kk>a.len[a.fa[nw]])?nw:a.fa[nw];
                }
              an[i]=kk;
            }
          b.clear();
          for(int i=1;i<=m;++i) b.inst(cc[i],0);
          b.v[0]=1;
          for(int i=1,nw=1;i<=m;++i)
            {
              int w=cc[i]-'a',p=nw=b.ch[nw][w];
              while(!b.v[p]&&b.len[p]>=an[i]) ans+=b.len[p]-max(b.len[b.fa[p]],an[i]),b.v[p]=1,p=b.fa[p];
            }
          printf("%lld
    ",ans);
        }
      return 0;
    }
    
  • 相关阅读:
    Jetson AGX Xavier初始化
    Jetson AGX Xavier更换apt-get源
    Mac远程访问Ubuntu
    Anaconda安装和环境的搭建
    C# NotifyIcon 托盘控件
    VS2010+OpenMP的简单使用
    VS2010+OpenCV3.4.1+zbar 64位
    datatbales 使用笔记
    ubuntu16.04 常用软件
    crontab不能正常执行的五种原因
  • 原文地址:https://www.cnblogs.com/smyjr/p/10123625.html
Copyright © 2011-2022 走看看