codeforces 700E 后缀数组

来源:互联网 发布:床品品牌知乎 编辑:程序博客网 时间:2024/06/11 04:31

题意:定义a串比b串优当且仅当a串中至少包含两个b串(可以重叠),给出一个串w,求一个最长的由w的子串构成的序列,满足第i个串比第i-1个串优。

题解后缀自动机没看懂,看了评论中的一个后缀数组做法。

定义一个串是好串当该串长度为1或该串的前缀和后缀都有同一个好串且该好串不出现在该串中间。
那么对于每一个后缀取一个最长的是后缀前缀的好串,最终答案一定由这些好串组成。

从n到1枚举求是当前串前缀的最长好串,在线段树上查询当前好串的前缀好串,用线段树维护已插入的编号最小值,查询前缀为前缀好串的最小编号。计算出当前好串的长度。在第一棵线段树上区间修改,第二棵线段树上单点修改。

说的不是很明白,看代码吧。。。

#include <bits/stdc++.h>using namespace std;#define N 210000#define ls l,mid,now<<1#define rs mid+1,r,now<<1|1int n,ans;char s[N];int tr[N],ran[N],sa[N],h[N][21],has[N],bir[N],val[N],deep[N];vector<int>v[N];int cmp(int x,int y,int k){    if(x+k>n||y+k>n)return 0;    return ran[x]==ran[y]&&ran[x+k]==ran[y+k];}void getsa(){    int i,cnt;    for(i=1;i<=n;i++)has[s[i]]++;    for(i=1,cnt=0;i<=128;i++)if(has[i])tr[i]=++cnt;    for(i=1;i<=128;i++)has[i]+=has[i-1];    for(i=1;i<=n;i++)ran[i]=tr[s[i]],sa[has[s[i]]--]=i;    for(int k=1;cnt!=n;k<<=1)    {        for(i=1;i<=n;i++)has[i]=0;        for(i=1;i<=n;i++)has[ran[i]]++;        for(i=1;i<=n;i++)has[i]+=has[i-1];        for(i=n;i>=1;i--)if(sa[i]>k)tr[sa[i]-k]=has[ran[sa[i]-k]]--;        for(i=1;i<=k;i++)tr[n-i+1]=has[ran[n-i+1]]--;        for(i=1;i<=n;i++)sa[tr[i]]=i;        for(i=1,cnt=0;i<=n;i++)tr[sa[i]]=cmp(sa[i],sa[i-1],k) ? cnt:++cnt;        for(i=1;i<=n;i++)ran[i]=tr[i];    }    for(int i=1;i<=n;i++)    {        if(ran[i]==1)continue;        for(int j=max(1,h[ran[i-1]][0]-1);;j++)        {            if(s[i+j-1]==s[sa[ran[i]-1]+j-1])h[ran[i]][0]=j;            else break;        }    }    for(int i=1;i<=n;i++)h[i][0]=h[i+1][0];}int rmq(int x,int y){    if(x==y)return n;    if(x>y)swap(x,y);y--;    int t=bir[y-x+1];    return min(h[x][t],h[y-(1<<t)+1][t]);}struct node{    int v,pos;    node(){}    node(int v,int pos):v(v),pos(pos){}    friend bool operator < (const node &r1,const node &r2)    {        if(r1.v==r2.v)return r1.pos>r2.pos;        return r1.v<r2.v;    };    friend bool operator > (const node &r1,const node &r2)    {        if(r1.v==r2.v)return r1.pos<r2.pos;        return r1.v>r2.v;    };}bj[N<<2];struct seg_tree1{    node query(int l,int r,int now,int pos)    {        if(l==r)return bj[now];        int mid=(l+r)>>1;        node ret=bj[now];        if(mid>=pos)return max(query(ls,pos),ret);        else return max(query(rs,pos),ret);    }    void update(int l,int r,int now,int lq,int rq,node v)    {        if(lq<=l&&r<=rq)            {bj[now]=max(bj[now],v);return;}        int mid=(l+r)>>1;        if(mid>=lq)update(ls,lq,rq,v);        if(mid<rq) update(rs,lq,rq,v);    }}tr1;struct seg_tree2{    int tr[N<<2];    void init(){memset(tr,0x3f,sizeof(tr));}    int query(int l,int r,int now,int lq,int rq)    {        if(lq<=l&&r<=rq)return tr[now];        int mid=(l+r)>>1,ret=n;        if(mid>=lq)ret=min(ret,query(ls,lq,rq));        if(mid<rq) ret=min(ret,query(rs,lq,rq));        return ret;    }    void update(int l,int r,int now,int pos,int v)    {        if(l==r)            {tr[now]=min(tr[now],v);return;}        int mid=(l+r)>>1;        if(mid>=pos)update(ls,pos,v);        else update(rs,pos,v);        tr[now]=min(tr[now<<1],tr[now<<1|1]);    }}tr2;int main(){    //freopen("tt.in","r",stdin);    scanf("%d",&n);scanf("%s",s+1);    getsa();    for(int i=1,j=0;i<=n;i++)    {        if((1<<j+1)<=i)j++;        bir[i]=j;    }    for(int i=1;i<=20;i++)        for(int j=1;j<=n;j++)            if(j+(1<<i)-1<=n)                h[j][i]=min(h[j][i-1],h[j+(1<<i-1)][i-1]);    tr2.init();    for(int i=n;i>=1;i--)    {        node t=tr1.query(1,n,1,ran[i]);        int l1,r1,l,r,pos;        l1=1;r1=ran[i];        while(l1<=r1)        {            int mid=(l1+r1)>>1;            if(rmq(mid,ran[i])<t.v)l1=mid+1;            else r1=mid-1;        }        l=l1;        l1=ran[i];r1=n;        while(l1<=r1)        {            int mid=(l1+r1)>>1;            if(rmq(ran[i],mid)<t.v)r1=mid-1;            else l1=mid+1;        }        r=r1;        if(t.v)        {            pos=tr2.query(1,n,1,l,r);            val[i]=pos+t.v-i;            deep[i]=deep[t.pos]+1;        }        else val[i]=1,deep[i]=1;        tr2.update(1,n,1,ran[i],i);        l1=1;r1=ran[i];        while(l1<=r1)        {            int mid=(l1+r1)>>1;            if(rmq(mid,ran[i])<val[i])l1=mid+1;            else r1=mid-1;        }        l=l1;        l1=ran[i];r1=n;        while(l1<=r1)        {            int mid=(l1+r1)>>1;            if(rmq(ran[i],mid)<val[i])r1=mid-1;            else l1=mid+1;        }        r=r1;        tr1.update(1,n,1,l,r,node(val[i],i));    }    for(int i=n;i>=1;i--)        ans=max(ans,deep[i]);    printf("%d\n",ans);    return 0;}
0 0
原创粉丝点击