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;
}
原文地址:https://www.cnblogs.com/smyjr/p/10123625.html