• SA练习题总结-篇一


    SA练习题总结-篇一

    专题链接

    总算是把(SA)相关的入门练习题做完了,也算是记下学习笔记,加深印象。

    A - Musical Theme

    POJ-1743

    给定长度为(n)的数组,询问不重复的相似序列(序列任意相邻两项差相等)的最长长度。
    换个说法就是,求最长的不重复且至少出现两次的子串。

    思路:

    这个题没什么好讲的,直接差分完求出(SA)数组。然后二分长度,利用(height)数组将之分组(这也是处理不重复的常规套路),这样保证每个组的(lcp)(geq)当前的二分长度。
    最后注意,因为是差分,所以直接把长度加1.

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    //#include <bits/stdc++.h>
    #include "iostream"
    #include "stdio.h"
    #include "string.h"
    #include "algorithm"
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int N=1e6+5;
    const ll mod=998244353;
    const double eps=1e-5;
    //const double pi=acos(-1);
    
    #define ls p<<1
    #define rs p<<1|1
    int s[N],a[N];
    int n,rk[N],sa[N],tp[N],m,tax[N];
    int height[N];
    void Rsort()
    {
        for(int i=0;i<=m;i++) tax[i]=0;
        for(int i=1;i<=n;i++) tax[rk[i]]++;
        for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
        for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void suffix()
    {
        m=300;
        for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
        Rsort();
        for(int w=1,p=0;p<n;w<<=1,m=p)
        {
            p=0;
            for(int i=1;i<=w;i++) tp[++p]=n-w+i;
            for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
            Rsort();
            swap(tp,rk);
            rk[sa[1]]=p=1;
            for(int i=2;i<=n;i++)
            {
                rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w]?p:++p);
            }
        }
        int k=0;
        for(int i=1;i<=n;i++)
        {
            if(k) --k;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k]) ++k;
            height[rk[i]]=k;
        }
    
    }
    bool check(int k)
    {
        int mx=0,mn=0x3f3f3f3f;
        for(int i=1;i<=n;i++)
        {
            if(height[i]<k)
                mx=mx=sa[i];
            else
            {
                mx=max(mx,max(sa[i],sa[i-1]));
                mn=min(mn,min(sa[i],sa[i-1]));
                if(mx-mn>k) return true;
            }
        }
        return false;
    }
    int main()
    {
        ios::sync_with_stdio(false);
        cin.tie(0);
        while(scanf("%d",&n)&&n)
        {
            for(int i=1;i<=n;i++) scanf("%d",&s[i]);
            for(int i=n;i>=2;i--) s[i]-=s[i-1]-88;
            s[1]=88;
            suffix();
            int l=0,r=n;
            while(l<r)
            {
                int mid=l+r+1>>1;
                if(check(mid)) l=mid;
                else r=mid-1;
            }
            printf("%d
    ",l>=4?l+1:0);
        }
    
        return 0;
    }
    

    B - Milk Patterns

    POJ-3261

    跟上个题差不多,不过是求至少出现(k)次的子串,同样要求不重复。

    思路:

    同上。

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    //#include <bits/stdc++.h>
    #include "iostream"
    #include "stdio.h"
    #include "string.h"
    #include "algorithm"
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int N=1e6+5;
    const ll mod=998244353;
    const double eps=1e-5;
    //const double pi=acos(-1);
    
    #define ls p<<1
    #define rs p<<1|1
    int s[N],a[N];
    int n,rk[N],sa[N],tp[N],m,tax[N];
    int height[N];
    void Rsort()
    {
        for(int i=0;i<=m;i++) tax[i]=0;
        for(int i=1;i<=n;i++) tax[rk[i]]++;
        for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
        for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void suffix()
    {
        m=1e6;
        for(int i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
        Rsort();
        for(int w=1,p=0;p<n;w<<=1,m=p)
        {
            p=0;
            for(int i=1;i<=w;i++) tp[++p]=n-w+i;
            for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
            Rsort();
            swap(tp,rk);
            rk[sa[1]]=p=1;
            for(int i=2;i<=n;i++)
            {
                rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w]?p:++p);
            }
        }
        int k=0;
        for(int i=1;i<=n;i++)
        {
            if(k) --k;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k]) ++k;
            height[rk[i]]=k;
        }
    
    }
    int check(int l)
    {
        int cnt=1,ans=0;
        for(int i=1;i<=n;i++)
        {
            if(height[i]<l)
            {
                ans=max(ans,cnt);
                cnt=1;
            }
            else cnt++;
        }
        return max(ans,cnt);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        int k;
        cin>>n>>k;
        for(int i=1;i<=n;i++) cin>>s[i];
        suffix();
        int l=0,r=n;
        while(l<r)
        {
            int mid=l+r+1>>1;
            if(check(mid)>=k) l=mid;
            else r=mid-1;
        }
        printf("%d
    ",l);
    
        return 0;
    }
    

    C - Distinct Substrings

    SPOJ-DISUBSTR

    这个题问的是本质不同的子串的个数。

    思路:

    (n)为字符串的长度,那么所有子串的个数为(frac{n*(n+1)}{2})
    然后只用减去重复的个数即可,这里也就是(sum height[i])(height[i])为后缀(sa[i])(sa[i-1])(lcp)

    //#pragma GCC optimize(2)
    //#pragma GCC optimize(3, "Ofast", "inline")
    //#include <bits/stdc++.h>
    #include "iostream"
    #include "stdio.h"
    #include "string.h"
    #include "algorithm"
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<int,int> pii;
    const int N=1e6+5;
    const ll mod=998244353;
    const double eps=1e-5;
    //const double pi=acos(-1);
    
    #define ls p<<1
    #define rs p<<1|1
    char s[N];
    int n,rk[N],sa[N],tp[N],m,tax[N];
    int height[N];
    void Rsort()
    {
        for(int i=0;i<=m;i++) tax[i]=0;
        for(int i=1;i<=n;i++) tax[rk[i]]++;
        for(int i=1;i<=m;i++) tax[i]+=tax[i-1];
        for(int i=n;i;i--) sa[tax[rk[tp[i]]]--]=tp[i];
    }
    void suffix()
    {
        m=60;
        for(int i=1;i<=n;i++) rk[i]=s[i]-'A'+1,tp[i]=i;
        Rsort();
        for(int w=1,p=0;p<n;w<<=1,m=p)
        {
            p=0;
            for(int i=1;i<=w;i++) tp[++p]=n-w+i;
            for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w;
            Rsort();
            swap(tp,rk);
            rk[sa[1]]=p=1;
            for(int i=2;i<=n;i++)
            {
                rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w]?p:++p);
            }
        }
        int k=0;
        for(int i=1;i<=n;i++)
        {
            if(k) --k;
            int j=sa[rk[i]-1];
            while(s[i+k]==s[j+k]) ++k;
            height[rk[i]]=k;
        }
    
    }
    int check(int l)
    {
        int cnt=1,ans=0;
        for(int i=1;i<=n;i++)
        {
            if(height[i]<l)
            {
                ans=max(ans,cnt);
                cnt=1;
            }
            else cnt++;
        }
        return max(ans,cnt);
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("in.txt", "r", stdin);
    #endif
        ios::sync_with_stdio(false);
        cin.tie(0);
        int _;
        cin>>_;
        while(_--)
        {
            cin>>(s+1);
            n=strlen(s+1);
            suffix();
            int ans=n*(n+1)/2;
            for(int i=1;i<=n;i++)
                ans-=height[i];
            cout<<ans<<endl;
        }
        return 0;
    }
    
  • 相关阅读:
    【阿里的感悟】质量该如何做? .(转载)
    java linux 配置环境
    Spring Bean属性绑定Bean返回值
    Spring BeanNameAutoProxyCreator 与 ProxyFactoryBean
    Spring Aop之(二)Aop 切面声明和通知
    Ubuntu开机自动启动Script
    转战博客园!
    linux 系统管理11 ——系统安全及应用
    linux awk
    Rsync数据同步工具
  • 原文地址:https://www.cnblogs.com/Suiyue-Li/p/12730921.html
Copyright © 2020-2023  润新知