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

    $SAM $ + 线段树合并

    先对 (S)(SAM) ;然后对于每一个串询问串 (T) ,首先在 (S)(SAM) 上跑出 (T) 的每个位置的最长匹配长度 (f[i]) ,即 (T[i-f[i]+1,i]) 是与 (S) 中的某个子串是匹配的(f[i]) 是最大的

    然后我们再对 (T) 建后缀自动机;对于一个点 (p) ,设 (posin { m endpos}(p)) ,对答案的贡献是 (max({ m len}(p)-max({ m len}(fa[p]),f[pos]),0)),因为 (f[pos]) 是最大的,所以这个点长度 (>f[pos]) 的串都可以贡献。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define R register int
    using namespace std;
    namespace Luitaryi {
    inline int g() { R x=0,f=1;
      register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
      do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
    } const int N=1000010,B=25;
    int m; ll ans;
    int d[N],mem[N];
    int cnt,rt[N],sum[N*B],ls[N*B],rs[N*B]; 
    inline void change(int& tr,int l,int r,int p) {
      if(!tr) tr=++cnt; ++sum[tr]; 
      if(l==r) return ; R md=(l+r)>>1;
      p<=md?change(ls[tr],l,md,p):change(rs[tr],md+1,r,p);
    }
    inline bool query(int tr,int l,int r,int LL,int RR) {
      if(LL<=l&&r<=RR) return sum[tr]; R md=(l+r)>>1;
      return (LL<=md&&ls[tr]&&query(ls[tr],l,md,LL,RR))
            ||(RR>md&&rs[tr]&&query(rs[tr],md+1,r,LL,RR));
    }
    inline int merge(int tr,int t,int l,int r) {
      if(!tr||!t) return tr+t;
      R p=++cnt,md=(l+r)>>1;
      sum[p]=sum[tr]+sum[t];
      if(l==r) return p;
      ls[p]=merge(ls[tr],ls[t],l,md);
      rs[p]=merge(rs[tr],rs[t],md+1,r);
      return p;
    }
    int f[N],pos[N];
    struct SAM {
      int tot,lst,n;
      int fa[N],c[N][26],len[N];
      inline void init() {
        memset(c,0,(tot+1)*104);
        memset(d,0,(n+1)<<2);
        memset(pos,0,(tot+1)<<2);
        memset(f,0,(n+1)<<2);
        tot=lst=1;
      }
      inline void add(int ch) {
        R p=lst,np=lst=++tot;
        len[np]=len[p]+1;
        while(p&&!c[p][ch]) c[p][ch]=np,p=fa[p];
        if(!p) return fa[np]=1,void();
        R q=c[p][ch];
        if(len[q]==len[p]+1) return fa[np]=q,void();
        R nq=++tot;
        memcpy(c[nq],c[q],26<<2);
        fa[nq]=fa[q],pos[nq]=pos[q],len[nq]=len[p]+1;
        fa[np]=fa[q]=nq;
        while(p&&c[p][ch]==q) c[p][ch]=nq,p=fa[p];
      }
    }s1,s2;
    char s[N];
    inline void calc(char* s,int LL,int RR) {
      R p=1,l=0;
      for(R i=1;i<=s2.n;++i) {
        R ch=s[i]-'a';
        while(20040109) {
          if(s1.c[p][ch]&&query(rt[s1.c[p][ch]],1,s1.n,LL+l,RR)) {
            p=s1.c[p][ch],++l; break;
          } if(!l) break; --l;
          if(l==s1.len[s1.fa[p]]) p=s1.fa[p];
        } f[i]=l;
      }
    }
    inline void main() {
      scanf("%s",s+1),s1.n=strlen(s+1),s1.init();
      for(R i=1;i<=s1.n;++i) 
        s1.add(s[i]-'a'),change(rt[s1.lst],1,s1.n,i);
      for(R i=1;i<=s1.tot;++i) ++d[s1.len[i]];
      for(R i=1;i<=s1.n;++i) d[i]+=d[i-1];
      for(R i=1;i<=s1.tot;++i) mem[d[s1.len[i]]--]=i;
      for(R i=s1.tot;i;--i) { R u=mem[i];
        rt[s1.fa[u]]=merge(rt[s1.fa[u]],rt[u],1,s1.n);
      } m=g(); for(R i=1,l,r;i<=m;++i) {
        scanf("%s",s+1),l=g(),r=g(),ans=0;
        s2.init(),s2.n=strlen(s+1);
        for(R j=1;j<=s2.n;++j) 
          s2.add(s[j]-'a'),pos[s2.lst]=j;
        calc(s,l,r);
        for(R j=2;j<=s2.tot;++j) 
          ans+=max(0,s2.len[j]-max(f[pos[j]],s2.len[s2.fa[j]]));
        printf("%lld
    ",ans);
      }
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    2020.01.10

  • 相关阅读:
    concurrent-锁
    字符串查找字符串
    指针作为函数返回值
    数组名作为函数参数
    指针和函数
    多级指针
    指针数组
    指针运算
    指针和数组
    const修饰的指针类型
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12177439.html
Copyright © 2011-2022 走看看