zoukankan      html  css  js  c++  java
  • BZOJ4310 跳蚤(后缀数组+二分答案)

      注意到答案一定是原串的子串,于是考虑造出SA,二分答案是第几小的子串。第k小子串很容易在SA上求出。之后计算使他成为最大子串至少要在几个位置切割,对每个字典序比答案大的后缀,找到所有合法切割位置(求lcp即可),就转化成了选最少的点使每个区间都包含至少一个点的经典问题。

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    #define N 100010
    #define ll long long
    int n,m,sa[N],sa2[N],rk[N<<1],tmp[N<<1],h[N],cnt[N],l[N];
    char s[N];
    ll tot=0;
    void make()
    {
        int m=0;
        for (int i=1;i<=n;i++) cnt[rk[i]=s[i]]++,m=max(m,(int)s[i]);
        for (int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
        for (int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i;
        for (int k=1;k<=n;k<<=1)
        {
            int p=0;
            for (int i=n-k+1;i<=n;i++) sa2[++p]=i;
            for (int i=1;i<=n;i++) if (sa[i]>k) sa2[++p]=sa[i]-k;
            memset(cnt,0,sizeof(cnt));
            for (int i=1;i<=n;i++) cnt[rk[i]]++;
            for (int i=1;i<=m;i++) cnt[i]+=cnt[i-1];
            for (int i=n;i>=1;i--) sa[cnt[rk[sa2[i]]]--]=sa2[i];
            memcpy(tmp,rk,sizeof(rk));
            p=rk[sa[1]]=1;
            for (int i=2;i<=n;i++)
            {
                if (tmp[sa[i]]!=tmp[sa[i-1]]||tmp[sa[i]+k]!=tmp[sa[i-1]+k]) p++;
                rk[sa[i]]=p;
            }
            if (p==n) break;
            m=p;
        }
        for (int i=1;i<=n;i++)
        {
            h[i]=max(h[i-1]-1,0);
            while (s[i+h[i]]==s[sa[rk[i]-1]+h[i]]) h[i]++;
        }
    }
    bool check(ll k)
    {
        int x=0;
        for (int i=1;i<=n;i++)
        if (k<=n-sa[i]+1-h[sa[i]]) {x=i;break;}
        else k-=n-sa[i]+1-h[sa[i]];
        k+=h[sa[x]];memset(l,0,sizeof(l));
        int lcp=k;if (k<n-sa[x]+1) l[sa[x]+lcp-1]=max(l[sa[x]+lcp-1],sa[x]);
        for (int i=x+1;i<=n;i++)
        {
            lcp=min(lcp,h[sa[i]]);
            if (!lcp) return 0;
            l[sa[i]+lcp-1]=max(l[sa[i]+lcp-1],sa[i]);
        }
        int t=1;
        for (int i=1;i<=n;i++)
        if (l[i])
        {
            t++;if (t>m) return 0;
            int x=i;while (x<n&&l[x+1]<=i) x++;
            i=x;
        }
        return 1;
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj4310.in","r",stdin);
        freopen("bzoj4310.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        m=read();
        scanf("%s",s+1);n=strlen(s+1);
        make();
        tot=1ll*n*(n+1)>>1;
        for (int i=1;i<=n;i++) tot-=h[i];
        ll l=1,r=tot,ans;
        while (l<=r)
        {
            ll mid=l+r>>1;
            if (check(mid)) r=mid-1,ans=mid;
            else l=mid+1;
        }
        for (int i=1;i<=n;i++)
        if (ans<=n-sa[i]+1-h[sa[i]]) {for (int j=sa[i];ans+h[sa[i]]>0;j++,ans--)printf("%c",s[j]);break;}
        else ans-=n-sa[i]+1-h[sa[i]];
        return 0;
    }
  • 相关阅读:
    Android 主题theme说明 摘记
    Android开发 去掉标题栏方法 摘记
    安卓项目五子棋代码详解(二)
    关于 ake sure class name exists, is public, and has an empty constructor that is public
    百度地图3.0实现图文并茂的覆盖物
    android onSaveInstanceState()及其配对方法。
    关于集成科大讯飞语音识别的 一个问题总结
    android 关于 webview 控制其它view的显示 以及更改view数据失败的问题总结
    C# 解析 json Newtonsoft果然强大,代码写的真好
    c#数据类型 与sql的对应关系 以及 取值范围
  • 原文地址:https://www.cnblogs.com/Gloid/p/9847092.html
Copyright © 2011-2022 走看看