CF700E Cool Slogans

题目:

CF700E Cool Slogans

题意:

给定一个字符串,要求构造字符串序列,满足任意都是的子串,且任意 ,都有中出现了至少次(可以有重叠部分,只要起始、结尾位置不同即可)。
求可能的最大的 的值(即序列的最大可能长度)。

题解:

要求的字符串序列一定是的子串的,再,再......

表示以开头的所有子串的最大值。

,当且仅当满足最大时的串的长度。

显然相同情况下肯定越小越好。

但是发现可以变小,来使也变小,来使可以转移。

突然发现,变小的一定和一个一样,使得代替,所以我们就不需要考虑变小这种情况了。

但是变小的会对产生影响,因为一个,一个。(假设变小后会被代替)

我们已经求出了了,但我们不知道是哪一个。我们要找出最小的满足

因为是单调不升的,所以满足一定满足

然后我们就可以在所有中找最小值,因为数组中是连续的一段,用线段树维护一下区间就好了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define gc getchar
//#define int long long
const int N=1e6+5;
int n,m,ans,c[N],x[N],y[N],sa[N],rk[N],height[N],Log[N],mi[N*4],st[N][20];
char a[N];
struct node{
    int f,len;
    node(){f=1;len=1;}
}tree[N*4];
bool operator < (node a,node b)
{
    if(a.f!=b.f)return a.f<b.f;
    return a.len>b.len;
}
//char buf[1<<21],*p1=buf,*p2=buf;
//inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
void SA(int n,int m)
{
    int p=0;
    for(int i=1;i<=m;i++)c[i]=0;
    for(int i=1;i<=n;i++)c[x[i]=a[i]]++;
    for(int i=1;i<=m;i++)c[i]+=c[i-1];
    for(int i=n;i;i--)sa[c[x[i]]--]=i;
    for(int i=1;i;i=i*2)
    {
        p=0;
        for(int j=n-i+1;j<=n;j++)y[++p]=j;
        for(int j=1;j<=n;j++)
            if(sa[j]>i)y[++p]=sa[j]-i;
        for(int j=1;j<=m;j++)c[j]=0;
        for(int j=1;j<=n;j++)c[x[y[j]]]++;
        for(int j=1;j<=m;j++)c[j]+=c[j-1];
        for(int j=n;j;j--)sa[c[x[y[j]]]--]=y[j];
        swap(x,y);
        x[sa[1]]=1;
        p=2;
        for(int j=2;j<=n;j++)
            if(y[sa[j]]==y[sa[j-1]]&&y[sa[j]+i]==y[sa[j-1]+i])x[sa[j]]=p-1;
            else x[sa[j]]=p++;
        if(p>n)return;
        m=p;
    }
}
void Height(int n)
{
    int k=0;
    for(int i=1;i<=n;i++)rk[sa[i]]=i;
    for(int i=1;i<=n;i++)
    {
        if(rk[i]==1)continue;
        if(k)k--;
        int j=sa[rk[i]-1];
        while(i+k<=n&&j+k<=n&&a[i+k]==a[j+k])k++;
        height[rk[i]]=k;
    }
}
void ST(int n)
{
    memset(st,0x3f,sizeof(st));
    for(int i=1;i<=n;i++)st[i][0]=height[i];
    for(int i=1;i<=Log[n];i++)
        for(int j=1;j+(1<<i)-1<=n;j++)
            st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
}
int LCP(int l,int r)
{
    if(l==r)return n;
    l++;
    int k=Log[r-l+1];
    return min(st[l][k],st[r-(1<<k)+1][k]);
}
void query(int x,int len,int &L,int &R)
{
    x=rk[x];
    int l=1,r=x;
    while(l<r)
    {
        int mid=(l+r)/2;
        if(LCP(mid,x)>=len)r=mid;
        else l=mid+1;
    }
    L=r;
    l=x,r=n;
    while(l<r)
    {
        int mid=(l+r+1)/2;
        if(LCP(x,mid)>=len)l=mid;
        else r=mid-1;
    }
    R=l;
}
void pushdown(int nod)
{
    tree[nod*2]=max(tree[nod*2],tree[nod]);
    tree[nod*2+1]=max(tree[nod*2+1],tree[nod]);
}
void change(int nod,int l,int r,int L,int R,node x)
{
    if(L>R||L>r||R<l)return;
    if(l==L&&r==R)
    {
        tree[nod]=max(tree[nod],x);
        return;
    }
    pushdown(nod);
    int mid=(l+r)/2;
    if(R<=mid)change(nod*2,l,mid,L,R,x);
    else if(L>mid)change(nod*2+1,mid+1,r,L,R,x);
    else{
        change(nod*2,l,mid,L,mid,x);
        change(nod*2+1,mid+1,r,mid+1,R,x);
    }
}
node find(int nod,int l,int r,int x)
{
    if(l==r)return tree[nod];
    pushdown(nod);
    int mid=(l+r)/2;
    if(x<=mid)return find(nod*2,l,mid,x);
    else return find(nod*2+1,mid+1,r,x);
}
void change2(int nod,int l,int r,int x)
{
    if(l==r)
    {
        mi[nod]=sa[x];
        return;
    }
    int mid=(l+r)/2;
    if(x<=mid)change2(nod*2,l,mid,x);
    else change2(nod*2+1,mid+1,r,x);
    mi[nod]=min(mi[nod*2],mi[nod*2+1]);
}
int find2(int nod,int l,int r,int L,int R)
{
    if(L>R||L>r||R<l)return 0x3f3f3f3f;
    if(l==L&&r==R)return mi[nod];
    int mid=(l+r)/2;
    if(R<=mid)return find2(nod*2,l,mid,L,R);
    else if(L>mid)return find2(nod*2+1,mid+1,r,L,R);
    else return min(find2(nod*2,l,mid,L,mid),find2(nod*2+1,mid+1,r,mid+1,R));
}
signed main()
{
    n=read();
    Log[0]=-1;
    for(int i=1;i<=n;i++)Log[i]=Log[i/2]+1;
    scanf("%s",a+1);
    SA(n,233);
    Height(n);
    ST(n);
    memset(mi,0x3f,sizeof(mi));
    for(int i=n;i;i--)
    {
        node xu=find(1,1,n,rk[i]);
//        cout<<xu.f<<" "<<xu.len<<endl;
        ans=max(ans,xu.f);
        if(xu.f!=1)
        {
            int L=0,R=0;
            query(i,xu.len,L,R);
            xu.len+=find2(1,1,n,L,R)-i;
        }
        xu.f++;
        int L=0,R=0;
        query(i,xu.len,L,R);
//        cout<<L<<" "<<R<<" "<<xu.f<<" "<<xu.len<<endl;
        change(1,1,n,L,R,xu);
        change2(1,1,n,rk[i]);
    }
    cout<<ans;
    return 0;
}
xuxuxuxuxu 文章被收录于专栏

信息学竞赛

全部评论

相关推荐

喜欢吃蛋糕仰泳鲈鱼是我的神:字节可以找个hr 给你挂了,再放池子捞
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务