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

  • 相关阅读:
    HDU 5791 Two (DP)
    POJ 1088 滑雪 (DPor记忆化搜索)
    LightOJ 1011
    POJ 1787 Charlie's Change (多重背包 带结果组成)
    HDU 5550 Game Rooms (ccpc2015 K)(dp)
    HDU 5542 The Battle of Chibi (ccpc 南阳 C)(DP 树状数组 离散化)
    HDU 5543 Pick The Sticks (01背包)
    HDU 5546 Ancient Go (ccpc2015南阳G)
    NB-IoT的DRX、eDRX、PSM三个模式 (转载,描述的简单易懂)
    MQTT 嵌入式端通讯协议解析(转)
  • 原文地址:https://www.cnblogs.com/Jackpei/p/12177439.html
Copyright © 2011-2022 走看看