• #P4770 [NOI2018]你的名字 的题解


    题目背景

    实力强大的小A 被选为了ION2018 的出题人,现在他需要解决题目的命名问题。

    题目描述

    小A 被选为了ION2018 的出题人,他精心准备了一道质量十分高的题目,且已经把除了题目命名以外的工作都做好了。

    由于ION 已经举办了很多届,所以在题目命名上也是有规定的,ION 命题手册规定:每年由命题委员会规定一个小写字母字符串,我们称之为那一年的命名串,要求每道题的名字必须是那一年的命名串的一个非空连续子串,且不能和前一年的任何一道题目的名字相同。

    由于一些特殊的原因,小A 不知道ION2017 每道题的名字,但是他通过一些特殊手段得到了ION2017 的命名串,现在小A 有Q 次询问:每次给定ION2017 的命名串和ION2018 的命名串,求有几种题目的命名,使得这个名字一定满足命题委员会的规定,即是ION2018 的命名串的一个非空连续子串且一定不会和ION2017 的任何一道题目的名字相同。

    由于一些特殊原因,所有询问给出的ION2017 的命名串都是某个串的连续子串,详细可见输入格式。

    输入格式

    第一行一个字符串S ,之后询问给出的ION2017 的命名串都是S 的连续子串。 第二行一个正整数Q,表示询问次数。 接下来Q 行,每行有一个字符串T 和两个正整数l,rl,r,表示询问如果ION2017 的 命名串是S [l..r]S[l..r],ION2018 的命名串是T 的话,有几种命名方式一定满足规定。

    输出格式

    输出Q 行,第i 行一个非负整数表示第i 个询问的答案。

    输入输出样例

    输入 

    1 scbamgepe
    2 3
    3 smape 2 7
    4 sbape 3 8
    5 sgepe 1 9
    View Code

    输出 

    1 12
    2 10
    3 4
    View Code

    题解

    • 分析

    我们考虑对于一个询问,先求出TT中本质不同的子串个数,然后减去是S(l,r)S(l,r)子串的。

    本质不同的子串个数,直接用height数组的性质就可以求。

    我们考虑,对于TT的每一个后缀,求出其最长的前缀长度LL,使得该后缀长度为LL的前缀是S(l,r)S(l,r)的子串。

    SS和所有TT连起来建后缀数组。为了方便计算每个询问,我们用链表的方法,记录每个位置在同一个串中的前驱后继。

    然后我们按顺序考虑TT的每一个后缀。

    如果aa位置的后缀的满足条件的最长前缀为LL,,则a+1a+1位置的至少为L-1L1。原理和求height数组相同,两边都同时去掉第一个字符,至少还留下L-1L1。

    所以考虑每个位置的话,用双指针扫描一下即可。

    然后,假如我们现在考虑位置aa的长度为LL的前缀是否可行,就是相当于在SS的[l,r-L+1][l,rL+1]内找一个位置bb,满足LCP(a,b)geqslant LLCP(a,b)L。

    满足LCP(a,b)geqslant LLCP(a,b)L条件的在后缀数组上的区间[ll,rr][ll,rr],可以二分,配合height数组的ST表在O(log n)O(logn)的时间内求出。

    然后问题转化为询问在后缀数组上的区间[ll,rr][ll,rr]内,是否存在一个在SS的[l,r-l+1][l,rl+1]中的字符。这个问题可以用建主席树然后询问,单次查询时间复杂度O(log n)O(logn)。

    对于一个位置,它与后缀数组上一个位置可能会算重,所以要减掉它们的LCPLCP。由于两个位置可能不连续,这部分也要用ST表来查。

    所以总时间复杂度O(nlog n)O(nlogn)。n=|S|+sum|T|n=S+T∣。

    • 代码

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<algorithm>
      4 #define N 500505
      5 #define M 1800505
      6 #define reg register
      7 #define lg2(x)(31-__builtin_clz(x))
      8 typedef long long LL;
      9 int n,sa[M],height[M],x[M],s[M],mgk,bel[M],m,QL[N],QR[N],y[M],st[22][M],nxt[M],head[N],node=0,rt[M],pp[M],len[N];
     10 int ls[M*20],rs[M*20],sz[M*20];
     11 char ss[N];
     12 bool isk;
     13 int _L,_R;
     14 void add(int&o,int pr,int l,int r,int pos){
     15     sz[o=++node]=sz[pr]+1;
     16     if(l<r){
     17         const int mid=l+r>>1;
     18         if(pos<=mid)add(ls[o],ls[pr],l,mid,pos),rs[o]=rs[pr];else add(rs[o],rs[pr],mid+1,r,pos),ls[o]=ls[pr];
     19     }
     20 }
     21 void sort(){
     22     int m=mgk,c[M];
     23     for(int i=1;i<=m;++i)c[i]=0;
     24     for(int i=1;i<=n;++i)++c[x[i]=s[i]];
     25     for(int i=1;i<=m;++i)c[i]+=c[i-1];
     26     for(int i=n;i;--i)sa[c[x[i]]--]=i;
     27     for(int k=1,p;k<=n;k<<=1){
     28         p=0;
     29         for(int i=n-k+1;i<=n;++i)y[++p]=i;
     30         for(reg int i=1;i<=n;++i)if(sa[i]>k)y[++p]=sa[i]-k;
     31         for(reg int i=1;i<=m;++i)c[i]=0;
     32         for(reg int i=1;i<=n;++i)++c[x[i]];
     33         for(reg int i=1;i<=m;++i)c[i]+=c[i-1];
     34         for(reg int i=n;i;--i)sa[c[x[y[i]]]--]=y[i];
     35         std::swap(x,y);
     36         x[sa[1]]=p=1;
     37         for(int i=2;i<=n;++i)
     38         x[sa[i]]=y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k]?p:++p;
     39         if(p==n)break;
     40         m=p;
     41     }
     42     for(int i=1,k=0;i<=n;++i)
     43     if(x[i]>1){
     44         k-=!!k;
     45         const int j=sa[x[i]-1];
     46         while(s[i+k]==s[j+k])++k;
     47         height[x[i]]=k;
     48     }
     49 }
     50 inline int find(int l,int r){
     51     if(l>r)return n;
     52     const int lg=lg2(r-l+1);
     53     return std::min(st[lg][l],st[lg][r-(1<<lg)+1]);
     54 }
     55 void init(){
     56     for(reg int i=1;i<=n;++i)st[0][i]=height[i];
     57     for(int i=0;i<21;++i)
     58     for(reg int j=1;j<=n;++j)
     59     if(j+(1<<i)<=n)st[i+1][j]=std::min(st[i][j],st[i][j+(1<<i)]);else break;
     60     int pre[N];
     61     memset(pre,0,sizeof pre);
     62     for(int i=1;i<=n;++i)
     63     if(s[sa[i]]<='z'){
     64         if(pre[bel[sa[i]]])
     65         nxt[pre[bel[sa[i]]]]=i,pp[i]=pre[bel[sa[i]]];else head[bel[sa[i]]]=i;
     66         pre[bel[sa[i]]]=i;
     67     }
     68 }
     69 void query(const int&ri,const int&le,int l,int r){
     70     if(sz[ri]==sz[le]||isk)return;
     71     if(_L<=l&&r<=_R)return(void)(isk=1);
     72     const int mid=l+r>>1;
     73     if(_L<=mid)query(ls[ri],ls[le],l,mid);
     74     if(mid<_R&&!isk)query(rs[ri],rs[le],mid+1,r);
     75 }
     76 bool check(int pos,int len,int l,int r){
     77     int L,ll,rr;
     78     ll=1,rr=pos-1;
     79     while(ll<=rr){
     80         const int mid=ll+rr>>1;
     81         if(find(mid+1,pos)>=len)rr=mid-1;else ll=mid+1;
     82     }
     83     L=rr;
     84     ll=pos+1,rr=n;
     85     while(ll<=rr){
     86         const int mid=ll+rr>>1;
     87         if(find(pos+1,mid)>=len)ll=mid+1;else rr=mid-1;
     88     }
     89     isk=0;
     90     _L=l,_R=r;
     91     query(rt[ll-1],rt[L],1,n);
     92     return isk;
     93 }
     94 int main(){
     95     memset(bel,-1,sizeof bel);
     96     mgk='z'+1;
     97     scanf("%s",ss);
     98     for(int i=0;ss[i];++i)
     99     s[++n]=ss[i],bel[n]=0;
    100     s[++n]=mgk++;
    101     scanf("%d",&m);
    102     for(int i=1;i<=m;++i){
    103         scanf("%s%d%d",ss,QL+i,QR+i);
    104         for(int j=0;ss[j];++j)
    105         s[++n]=ss[j],bel[n]=i;
    106         len[i]=n;
    107         s[++n]=mgk++;
    108     }
    109     sort();
    110     init();
    111     for(reg int i=1;i<=n;++i)
    112     if(!bel[sa[i]])add(rt[i],rt[i-1],1,n,sa[i]);else rt[i]=rt[i-1];
    113     for(int i=1;i<=m;++i){
    114         LL ans=len[i]-sa[head[i]]+1;
    115         int mnid=sa[head[i]];
    116         for(int j=nxt[head[i]];j;j=nxt[j]){
    117             ans+=len[i]-sa[j]+1;
    118             ans-=find(pp[j]+1,j);
    119             mnid=std::min(mnid,sa[j]);
    120         }
    121         for(int j=mnid,L=mnid;s[j]<='z';++j){
    122             if(L<j)L=j;
    123             while(s[L]<='z'&&check(x[j],L-j+1,QL[i],QR[i]-L+j))++L;
    124             if(x[j]!=head[i])ans-=std::max(L-j-find(pp[x[j]]+1,x[j]),0);else
    125             ans-=L-j;
    126         }
    127         printf("%lld
    ",ans);
    128     }
    129     return 0;
    130 }
    View Code
  • 相关阅读:
    tp5中的一些小方法
    jquery 中的一写常用方法
    tp5文件上传
    使用json格式输出
    第十六篇:泛型算法结构
    第十五篇:流迭代器 + 算法灵活控制IO流
    第十四篇:一个文本查询程序的实现
    第十三篇:multimap容器和multiset容器中的find操作
    poj 2516(拆点+最小权匹配)
    poj 3686(拆点+最小权匹配)
  • 原文地址:https://www.cnblogs.com/ssf-lrk/p/11249875.html
Copyright © 2020-2023  润新知