• 后缀数组


    具体请看论文....

    POJ 1743 Musical Theme

    不重叠的最长重复子串

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 20100
    int p[N];
    int sa[N],rank[N],height[N];
    int wa[N],wb[N],c[N];
    //sa[i] 表示排名为i的下标
    //rank[i]表示i的排名
    //height[i]表示sa[i]和sa[i-1]的最长前缀
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        //初始化基数排序
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
    
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            //y[i] 表示第二关键字排名为i的下标
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            //如果后缀长度不到j的,第二关键字排名靠前
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            //sa[i] < j的时候不可能为第二关键字,位置sa[i]-j的第二关键字为sa[i],
            //他的排名为p
    
            //按第一关键字排序
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            //按y数组的存的下标顺序,基数排序
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
    
            swap(x,y);
            //生成新的x数组,交换成y,是为了节省空间....
            p = 1;x[sa[0]] = 0;
            //如果两个关键字都一样,下次的第一关键字一样。
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        //看论文,有证明
        for(i = 0;i < n;i ++)
        {
            if(k) k--;
            j = sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int judge(int mid,int n)
    {
        int minz,maxz,i;
        minz = maxz = sa[1];
        for(i = 2;i <= n;i ++)
        {
            if(height[i] < mid)
            {
                minz = maxz = sa[i];
            }
            else
            {
                maxz = max(maxz,sa[i]);
                minz = min(minz,sa[i]);
                if(maxz-minz > mid)
                return 1;
            }
        }
        return 0;
    }
    int main()
    {
        int n,i;
        while(scanf("%d",&n)!=EOF)
        {
            if(n == 0) break;
            for(i = 0;i < n;i ++)
            scanf("%d",&p[i]);
            for(i = 0;i < n-1;i ++)
            p[i] = p[i+1] -  p[i] + 90;
            n --;
            p[n] = 0;
            build_sa(p,n+1,200);
            get_height(p,n);
            int str,mid,end;
            str = 1;
            end = n/2;
            while(str < end)
            {
                mid = (str+end + 1)/2;
                if(judge(mid,n))
                str = mid;
                else
                end = mid-1;
            }
            if(end >= 4)
            printf("%d
    ",end+1);
            else
            printf("0
    ");
        }
        return 0;
    }
    View Code

     POJ 3261 Milk Patterns

    数据非常水,本意是可重叠k次最长子串。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 20100
    int p[N];
    int sa[N],rank[N],height[N];
    int wa[N],wb[N],c[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k--;
            j = sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int judge(int mid,int n,int k)
    {
        int flag,i;
        flag = 1;
        for(i = 2;i <= n;i ++)
        {
            if(height[i] < mid)
            {
                if(flag >= k) return 1;
                flag = 1;
            }
            else
            {
                flag ++;
            }
        }
        if(flag >= k)
        return 1;
        else
        return 0;
    }
    int main()
    {
        int n,i,maxz,k;
        while(scanf("%d%d",&n,&k)!=EOF)
        {
            maxz = 0;
            for(i = 0;i < n;i ++)
            {
                scanf("%d",&p[i]);
                p[i] ++;
                maxz = max(maxz,p[i]);
            }
            p[n] = 0;
            build_sa(p,n+1,maxz+20);
            get_height(p,n);
            int str,mid,end;
            str = 1;
            end = n/2;
            while(str < end)
            {
                mid = (str+end + 1)/2;
                if(judge(mid,n,k))
                str = mid;
                else
                end = mid-1;
            }
            printf("%d
    ",end);
        }
        return 0;
    }
    View Code

     POJ 2774 Long Long Message

    注意把C数组开到N....傻了...

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 200100
    int sa[N],rank[N],height[N];
    int c[N],wa[N],wb[N];
    char s1[N],s2[N];
    int p[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i]-j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int main()
    {
        int i,len1,len2,j,n;
        scanf("%s%s",s1,s2);
        len1 = strlen(s1);
        j = 0;
        for(i = 0;i < len1;i ++)
        p[j++] = s1[i]-'a'+1;
        p[j++] = 28;
        len2 = strlen(s2);
        for(i = 0;i < len2;i ++)
        p[j++] = s2[i]-'a'+1;
        p[j] = 0;
        n = j;
        build_sa(p,n+1,30);
        get_height(p,n);
        int ans = 0;
        for(i = 1;i <= n;i ++)
        {
            if(sa[i] < len1&&sa[i-1] > len1)
            ans = max(ans,height[i]);
            if(sa[i] > len1&&sa[i-1] < len1)
            ans = max(ans,height[i]);
        }
        printf("%d
    ",ans);
        return 0;
    }
    View Code

     POJ 3294 Life Forms

    感觉复杂度挺高的,n=1的时候需要特判。写的代码有些乱....

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    #define N 200100
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N];
    char str[101][1101];
    int flag[N];
    int o[101];
    int t;
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0; i < m; i ++)
            c[i] = 0;
        for(i = 0; i < n; i ++)
            c[x[i] = s[i]] ++;
        for(i = 1; i < m; i ++)
            c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)
            sa[--c[x[i]]] = i;
        for(j = 1; j <= n; j <<= 1)
        {
            p = 0;
            for(i = n-j; i < n; i ++)
                y[p++] = i;
            for(i = 0; i < n; i ++)
                if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0; i < m; i ++)
                c[i] = 0;
            for(i = 0; i < n; i ++)
                c[x[y[i]]] ++;
            for(i = 1; i < m; i ++)
                c[i] += c[i-1];
            for(i = n-1; i >= 0; i --)
                sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1; i < n; i ++)
                x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1; i <= n; i ++)
            rank[sa[i]] = i;
        for(i = 0; i < n; i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int judge(int mid,int n)
    {
        int i,j;
        memset(o,0,sizeof(o));
        o[flag[sa[1]]] = 1;
        for(i = 2; i <= n; i ++)
        {
            if(height[i] < mid)
            {
                int temp = 0;
                for(j = 1; j <= t; j ++)
                {
                    if(o[j]) temp ++;
                    o[j] = 0;
                }
                if(temp > t/2)
                    return 1;
                o[flag[sa[i]]] = 1;
            }
            else
            {
                o[flag[sa[i]]] = 1;
            }
        }
        int temp = 0;
        for(j = 1; j <= t; j ++)
        {
            if(o[j]) temp ++;
            o[j] = 0;
        }
        if(temp > t/2)
            return 1;
        return 0;
    }
    void fun(int key,int end)
    {
        int temp = 0,i;
        for(i = 1; i <= t; i ++)
        {
            if(o[i]) temp ++;
            o[i] = 0;
        }
        if(temp > t/2)
        {
            for(i = 0; i < end; i ++)
            {
                printf("%c",p[sa[key]+i]-1+'a');
            }
            printf("
    ");
        }
    }
    int main()
    {
        int n,i,j,len,num,temp,f;
        f = 0;
        while(scanf("%d",&n)!=EOF)
        {
            t = n;
            if(f)printf("
    ");
            f = 1;
            if(n == 0) break;
            num = 0;
            temp = 30;
            for(i = 0; i < n; i ++)
            {
                scanf("%s",str[i]);
                len = strlen(str[i]);
                for(j = 0; j < len; j ++)
                {
                    flag[num] = i+1;
                    p[num++] = str[i][j]-'a'+1;
                }
                flag[num] = 0;
                if(i != n-1)
                    p[num++] = temp++;
                else
                    p[num] = 0;
            }
            if(n == 1)
            {
                printf("%s
    ",str[0]);
                continue;
            }
            build_sa(p,num+1,temp+10);
            get_height(p,num);
            int str,end,mid;
            str = 0;
            end = 5000;
            //for(i = 1;i <= num;i ++)
            //printf("%d ",height[i]);
            while(str < end)
            {
                mid = (str + end + 1)/2;
                if(judge(mid,num))
                    str = mid;
                else
                    end = mid - 1;
            }
            if(end == 0)
            {
                printf("?
    ");
                continue;
            }
            int sz[101];
            memset(sz,0,sizeof(sz));
            memset(o,0,sizeof(o));
            o[flag[sa[1]]] = 1;
            for(i = 2; i <= num; i ++)
            {
                if(height[i] < end)
                {
                    fun(i-1,end);
                    o[flag[sa[i]]] = 1;
                }
                else
                {
                    o[flag[sa[i]]] = 1;
                }
            }
            fun(num,end);
        }
        return 0;
    }
    View Code

     POJ 3974 Palindrome

    最长回文串,跑的有些慢...

    这份代码 是水过的,我找的是相邻的最大值并且两个后缀必须在前面或后面,但是abcdba会把abba当成回闻....这题如果改成rmq的话,目测会MLE+TLE,放弃治疗了。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 2010000
    char str[1000001];
    int sa[N],height[N],rank[N];
    int p[N],c[N],wa[N],wb[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            j = sa[rank[i]-1];
            if(k) k--;
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int main()
    {
        int i,len,n,cas = 1;
        while(scanf("%s",str)!=EOF)
        {
            if(strcmp(str,"END") == 0) break;
            n = 0;
            len = strlen(str);
            for(i = 0;i < len;i ++)
            p[n++] = str[i]-'a'+1;
            p[n++] = 28;
            for(i = 0;i < len;i ++)
            p[n++] = str[len-i-1]-'a'+1;
            p[n] = 0;
            build_sa(p,n+1,30);
            get_height(p,n);
            int ans = 0;
            for(i = 1;i <= n;i ++)
            {
                if(sa[i-1] < len||sa[i] > len)
                ans = max(ans,height[i]);
                if(sa[i-1] > len||sa[i] < len)
                ans = max(ans,height[i]);
            }
            printf("Case %d: %d
    ",cas++,ans);
        }
        return 0;
    }
    View Code

     URAL 1297. Palindrome

    最长回文串,这是正解。rmq+后缀数组,调试了好一会,费劲啊!!

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 2010000
    int sa[N],height[N],Rank[N];
    int c[N],p[N],wa[N],wb[N];
    int bin[31];
    int minz[22][N];
    char str[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0; i < m; i ++)
            c[i] = 0;
        for(i = 0; i < n; i ++)
            c[x[i] = s[i]] ++;
        for(i = 1; i < m; i ++)
            c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)
            sa[--c[x[i]]] = i;
        for(j = 1; j <= n; j <<= 1)
        {
            p = 0;
            for(i = n-j; i < n; i ++)
                y[p++] = i;
            for(i = 0; i < n; i ++)
                if(sa[i] >= j) y[p++] = sa[i]-j;
    
            for(i = 0; i < m; i ++)
                c[i] = 0;
            for(i = 0; i < n; i ++)
                c[x[y[i]]] ++;
            for(i = 1; i < m; i ++)
                c[i] += c[i-1];
            for(i = n-1; i >= 0; i --)
                sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1; i < n; i ++)
                x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1; i <= n; i ++)
            Rank[sa[i]] = i;
        for(i = 0; i < n; i ++)
        {
            if(k) k --;
            j = sa[Rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[Rank[i]] = k;
        }
    }
    void init(int n)
    {
        int i,j;
        for(i = 1; i <= n; i ++)
            minz[0][i] = height[i];
        for(i = 1; bin[i] <= n; i ++)
        {
            for(j = 1; j + bin[i-1] <= n; j ++)
            {
                minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);
            }
        }
    }
    int rmq(int s,int t)
    {
        int k = log((t-s+1)*1.0)/log(2.0);
        return min(minz[k][s],minz[k][t-bin[k]+1]);
    }
    int main()
    {
        int i,len,n;
        scanf("%s",str);
        n = 0;
        len = strlen(str);
        for(i = 0; i < len; i ++)
            p[n++] = str[i]+1;
        p[n++] = 299;
        for(i = 0; i < len; i ++)
            p[n++] = str[len-i-1]+1;
        p[n] = 0;
        build_sa(p,n+1,300);
        get_height(p,n);
        for(i = 0; i < 21; i ++)
            bin[i] = 1<<i;
        init(n);
        int s,t,temp,pos,ans = 0;
        for(i = 0; i < len; i ++)
        {
            s = Rank[i+1];
            t = Rank[2*len-i];
            if(s > t) swap(s,t);
            s ++;
            temp = rmq(s,t)*2;
            if(ans < temp)
            {
                ans = temp;
                pos = i - temp/2 + 1;
            }
            s = Rank[i];
            t = Rank[2*len-i];
            if(s > t) swap(s,t);
            s ++;
            temp = rmq(s,t)*2 - 1;
            if(ans < temp)
            {
                ans = temp;
                pos = i - temp/2;
            }
        }
        for(i = 0;i < ans;i ++)
        printf("%c",str[pos+i]);
        return 0;
    }
    View Code

     POJ 3693 Maximum repetition substring

     可能是水过,看论文上的讲解,完全还是不会啊....

    枚举那里看懂了,寻找L*i和L*(i+1)往前最长和往后最长,不知道怎么操作的。不会是把字符串倒过来然后再处理一遍吧。。。往后的很简单,就是height最小值,往前就有点扯了,知道后面的长度x,如果前面的长度大于L- x%L那么就会总长度会+1,总长度+2那些个情况应该是不用考虑的,枚举前面的时候已经算了。还有字典序,完全是乱搞,看了一个大神写的是吧L保存下来,然后枚举sa,判断是否可行.....做个题真难啊....

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 100100
    int bin[30];
    int sa[N],height[N],rank[N];
    int c[N],p[N],wa[N],wb[N];
    char str[N];
    int minz[22][N];
    int que[10001];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i]-j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    void init(int n)
    {
        int i,j;
        for(i = 1;i <= n;i ++)
        minz[0][i] = height[i];
        for(i = 1;bin[i] <= n;i ++)
        {
            for(j = 1;j +bin[i-1] <= n;j ++)
            {
                minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);
            }
        }
    }
    int rmq(int s,int t)
    {
        s = rank[s];
        t = rank[t];
        if(s > t) swap(s,t);
        s ++;
        int k = log((t-s+1)*1.0)/log(2.0);
        return min(minz[k][s],minz[k][t-bin[k]+1]);
    }
    int main()
    {
        int cas = 1,len,i,j;
        for(i = 0;i <= 20;i ++)
        bin[i] = 1<<i;
        while(scanf("%s",str)!=EOF)
        {
            if(str[0] == '#') break;
            len = strlen(str);
            for(i = 0;i < len;i ++)
            p[i] = str[i] - 'a'+1;
            p[len] = 0;
            build_sa(p,len+1,30);
            get_height(p,len);
            init(len);
            int ans = 0,num = 0;
            for(i = 1;i <= len;i ++)
            {
                for(j = 0;j < len;j += i)
                {
                    if(j+i >= len) continue;
                    int temp,lf,res;
                    res = 0;
                    temp = rmq(j,j+i);
                    res = max(res,temp/i+1);
                    lf = i - temp%i;
                    if(j-lf >= 0)
                    {
                        temp = rmq(j-lf,j-lf+i);
                        if(temp >= lf)
                        res = max(res,temp/i+1);
                    }
                    if(ans < res)
                    {
                        ans = res;
                        num = 0;
                        que[num++] = i;
                    }
                    else if(ans == res)
                    {
                        if(que[num-1] == i) continue;
                        que[num++] = i;
                    }
                }
            }
            int pos,lt;
            for(i = 1;i <= len;i ++)
            {
                for(j = 0;j < num;j ++)
                {
                    int temp = que[j];
                    if(rmq(sa[i],sa[i]+temp) >= (ans-1)*temp)
                    {
                        pos = sa[i];
                        lt = temp*ans;
                        break;
                    }
                }
                if(j != num) break;
            }
            printf("Case %d: ",cas++);
            for(i = 0;i < lt;i ++)
            printf("%c",str[pos+i]);
            printf("
    ");
        }
        return 0;
    }
    View Code

     POJ 3581 Sequence

    很棒的一个题,把一个数字串分为三部分,翻转。特别注意第一个数字最大,倒序之后,最小的后缀,一定是最小的数字开头的,因为最后一个数字为最大,不存在下面这种情况。

    后面就是分成两段的情况了,选最小并不一定对。

    如 5 0 5 0 2 3 倒过来之后 3 2 0 5 0 5

    0 5

    0 5 0 5

    ...

    这样选最小的并不一定最好, 0 5  和0 5 0 5前面是一样的。0 5后面其实要比较后一部分的字典序。

    做法看这个博客:http://www.cnblogs.com/zcwwzdjn/archive/2012/03/10/2389413.html

    就是再复制一遍,注意保证分成两部分sa[i]>=1,这题不用中间隔开字符,要理解思想啊....

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 201000
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N],que[N];
    int ans[4];
    struct node
    {
        int x,id;
    } num[N];
    bool cmp(node a,node b)
    {
        return a.x < b.x;
    }
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0; i < m; i ++)
            c[i] = 0;
        for(i = 0; i < n; i ++)
            c[x[i] = s[i]] ++;
        for(i = 1; i < m; i ++)
            c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)
            sa[--c[x[i]]] = i;
        for(j = 1; j <= n; j <<= 1)
        {
            p = 0;
            for(i = n-j; i < n; i ++)
                y[p++] = i;
            for(i = 0; i < n; i ++)
                if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0; i < m; i ++)
                c[i] = 0;
            for(i = 0; i < n; i ++)
                c[x[y[i]]] = 0;
            for(i = 1; i < m; i ++)
                c[i] += c[i-1];
            for(i = n-1; i >= 0; i --)
                sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1; i < n; i ++)
                x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    int main()
    {
        int n,i,temp,tn;
        scanf("%d",&n);
        tn = n;
        for(i = 0; i < n; i ++)
        {
            scanf("%d",&num[i].x);
            que[n-i-1] = num[i].x;
            num[i].id = n-i-1;
        }
        sort(num,num+n,cmp);
        temp = 2;
        p[num[0].id] = 1;
        for(i = 1; i < n; i ++)
        {
            p[num[i].id] = num[i-1].x == num[i].x?temp-1:temp++;
        }
        p[n] = 0;
        build_sa(p,n+1,temp+10);
        ans[0] = 1000000;
        for(i = 1; i <= n; i ++)
        {
            if(sa[i] >= 2)
            {
                ans[1] = sa[i];
                break;
            }
        }
        n = ans[1];
        for(i = 0; i < ans[1]; i ++)
            p[n++] = p[i];
        p[n] = 0;
        build_sa(p,n+1,temp+10);
        for(i = 1; i <= n; i ++)
        {
            if(sa[i] < ans[1]&&sa[i] >= 1)
            {
                ans[2] = sa[i];
                break;
            }
        }
        for(i = ans[1]; i < tn; i ++)
            printf("%d
    ",que[i]);
        for(i = ans[2]; i < ans[1]; i ++)
            printf("%d
    ",que[i]);
        for(i = 0; i < ans[2]; i ++)
            printf("%d
    ",que[i]);
        return 0;
    }
    View Code

     HDU 4416 Good Article Good sentence

    RE了很多次....注意n = 0,数组开小,最后结果LL。

    A出现过,B[]没出现的字串。

    论文里有求子串的个数,这题麻烦一点,后缀排序后对于sa[i] 要减去前面出现过的和后面出现过的。前面出现过的值肯定是height[i],无论sa[i-1]是A里面的,还是B[]里面的,height[i]是最大值,保证A#B...保证这个#是字典序是次小的,保证了A的相对顺序不变, 再从j+1寻找第一个B[]的后缀,那么rmq(i+1,pos)就是sa[i]后面出现过的,取 max就好,那个rmq从后往前倒着标记一遍就可以求出来。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 501000
    #define LL __int64
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N];
    int res[N];
    char str[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k--;
            j = sa[rank[i]-1];
            while(s[i+k]==s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int main()
    {
        int t,cas = 1,i,temp,len,tlen,num;
        int n,j;
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n);
            num = 0;
            for(i = 0;i <= n;i ++)
            {
                scanf("%s",str);
                if(i == 0)
                len = strlen(str);
                tlen = strlen(str);
                for(j = 0;j < tlen;j ++)
                {
                    p[num++] = str[j]-'a'+2+n;
                }
                if(i == n)
                p[num] = 0;
                else
                p[num++] = i+1;
            }
            build_sa(p,num+1,n+30);
            get_height(p,num);
            LL ans = 0;
            temp = 0;
            for(i = num;i >= 1;i --)
            {
                if(sa[i] < len)
                {
                    res[i] = temp;
                    temp = min(height[i],res[i]);
                }
                else
                temp = height[i];
            }
            for(i = 1;i <= num;i ++)
            {
                if(sa[i] < len)
                {
                    ans += len - sa[i] - max(height[i],res[i]);
                }
            }
            printf("Case %d: %I64d
    ",cas++,ans);
        }
        return 0;
    }
    View Code

     HDU 3518 Boring counting

    水题....

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 1100
    #define LL __int64
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N];
    char str[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int main()
    {
        int i,j,len,maxz,minz;
        while(scanf("%s",str)!=EOF)
        {
            if(str[0] == '#') break;
            len = strlen(str);
            for(i = 0;i < len;i ++)
            p[i] = str[i] - 'a' + 1;
            p[len] = 0;
            build_sa(p,len+1,30);
            get_height(p,len);
            int ans = 0;
            for(i = 1;i <= len;i ++)
            {
                maxz = sa[1];
                minz = sa[1];
                for(j = 2;j <= len;j ++)
                {
                    if(height[j] < i)
                    {
                        if(minz+i <= maxz) ans ++;
                        maxz = sa[j];
                        minz = sa[j];
                    }
                    else
                    {
                        maxz = max(maxz,sa[j]);
                        minz = min(minz,sa[j]);
                    }
                }
                if(minz+i <= maxz) ans ++;
            }
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

     HDU 4080 Stammering Aliens

    注意n = 1的特殊情况。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N  100000
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N];
    char str[N];
    int m;
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0; i < m; i ++)
            c[i] = 0;
        for(i = 0; i < n; i ++)
            c[x[i] = s[i]] ++;
        for(i = 1; i < m; i ++)
            c[i] += c[i-1];
        for(i = n-1; i >= 0; i --)
            sa[--c[x[i]]] = i;
        for(j = 1; j <= n; j <<= 1)
        {
            p = 0;
            for(i = n-j; i < n; i ++)
                y[p++] = i;
            for(i = 0; i < n; i ++)
                if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0; i < m; i ++)
                c[i] = 0;
            for(i = 0; i < n; i ++)
                c[x[y[i]]] ++;
            for(i = 1; i < m; i ++)
                c[i] += c[i-1];
            for(i = n-1; i >= 0; i --)
                sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1; i < n; i ++)
                x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1; i <= n; i ++)
            rank[sa[i]] = i;
        for(i = 0; i < n; i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    int judge(int mid,int n)
    {
        int i,flag = 1;
        for(i = 1; i <= n; i ++)
        {
            if(height[i] < mid)
            {
                if(flag >= m) return 1;
                flag = 1;
            }
            else
                flag ++;
        }
        if(flag >= m)
            return 1;
        else
            return 0;
    }
    int main()
    {
        int i,len;
        while(scanf("%d",&m)!=EOF)
        {
            if(m == 0) break;
            scanf("%s",str);
            len = strlen(str);
            if(m == 1)
            {
                printf("%d %d
    ",len,0);//特判
                continue;
            }
            for(i = 0; i < len; i ++)
            {
                p[i] = str[i] - 'a' + 1;
            }
            p[len] = 0;
            build_sa(p,len+1,30);
            get_height(p,len);
            int str,end,mid;
            str = 0;
            end = len;
            while(str < end)
            {
                mid = (str + end + 1)/2;
                if(judge(mid,len))
                    str = mid;
                else
                    end = mid - 1;
            }
            if(end == 0)
            {
                printf("none
    ");
                continue;
            }
            printf("%d ",end);
            int flag = 1,temp = sa[1],ans;
            ans = 0;
            for(i = 1; i <= len; i ++)
            {
                if(height[i] < end)
                {
                    if(flag >= m)
                    ans = max(ans,temp);
                    temp = sa[i];
                    flag = 1;
                }
                else
                {
                    temp = max(temp,sa[i]);
                    flag ++;
                }
            }
            if(flag >= m)
            ans = max(ans,temp);
            printf("%d
    ",ans);
        }
        return 0;
    }
    View Code

     HDU 4691 Front compression

    想了好一会,发现 不会啊。。。。原来看错题了。。。这个比较只是相邻的....挺水的....

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <cmath>
    using namespace std;
    #define N 300000
    #define LL __int64
    int sa[N],height[N],rank[N];
    int c[N],wa[N],wb[N];
    int p[N],sum[N];
    int minz[22][N];
    int bin[22];
    char str[N];
    void build_sa(int s[],int n,int m)
    {
        int i,j,p,*x = wa,*y = wb;
        for(i = 0;i < m;i ++)
        c[i] = 0;
        for(i = 0;i < n;i ++)
        c[x[i] = s[i]] ++;
        for(i = 1;i < m;i ++)
        c[i] += c[i-1];
        for(i = n-1;i >= 0;i --)
        sa[--c[x[i]]] = i;
        for(j = 1;j <= n;j <<= 1)
        {
            p = 0;
            for(i = n-j;i < n;i ++)
            y[p++] = i;
            for(i = 0;i < n;i ++)
            if(sa[i] >= j) y[p++] = sa[i] - j;
            for(i = 0;i < m;i ++)
            c[i] = 0;
            for(i = 0;i < n;i ++)
            c[x[y[i]]] ++;
            for(i = 1;i < m;i ++)
            c[i] += c[i-1];
            for(i = n-1;i >= 0;i --)
            sa[--c[x[y[i]]]] = y[i];
            swap(x,y);
            p = 1;
            x[sa[0]] = 0;
            for(i = 1;i < n;i ++)
            x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;
            if(p >= n) break;
            m = p;
    
        }
    }
    void get_height(int s[],int n)
    {
        int i,j,k = 0;
        for(i = 1;i <= n;i ++)
        rank[sa[i]] = i;
        for(i = 0;i < n;i ++)
        {
            if(k) k --;
            j = sa[rank[i]-1];
            while(s[i+k] == s[j+k]) k ++;
            height[rank[i]] = k;
        }
    }
    void init(int n)
    {
        int i,j;
        for(i = 1;i <= n;i ++)
        minz[0][i] = height[i];
        for(i = 1;i <= bin[i];i ++)
        {
            for(j = 1;j + bin[i-1] <= n;j ++)
            {
                minz[i][j] = min(minz[i-1][j],minz[i-1][j+bin[i-1]]);
            }
        }
    }
    int rmq(int s,int t)
    {
        s = rank[s];t = rank[t];
        if(s > t) swap(s,t);
        s ++;
        int k = log((t-s+1)*1.0)/log(2.0);
        return min(minz[k][s],minz[k][t-bin[k]+1]);
    }
    int fun(int num)
    {
        int ans = 0;
        if(num == 0) return 1;
        while(num)
        {
            num /= 10;
            ans ++;
        }
        return ans;
    }
    int main()
    {
        int i,len,n,l,r,pl,pr;
        for(i = 0;i <= 20;i ++)
        bin[i] = 1<<i;
        while(scanf("%s",str)!=EOF)
        {
            len = strlen(str);
            for(i = 0;i < len;i ++)
            {
                p[i] = str[i] - 'a' + 1;
            }
            p[len] = 0;
            build_sa(p,len+1,30);
            get_height(p,len);
            init(len);
            scanf("%d",&n);
            LL ans1,ans2;
            int num,temp;
            ans1 = ans2 = 0;
            pl = pr = 0;
            for(i = 0;i < n;i ++)
            {
                scanf("%d%d",&l,&r);
                ans1 += r - l + 1;
                if(pl == l)
                temp = len - l;
                else
                temp = rmq(pl,l);
                num = min(pr-pl,min(temp,r-l));
                ans2 += fun(num) + 2 + r - l - num;
                pl = l;
                pr = r;
            }
            printf("%I64d %I64d
    ",ans1,ans2);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    [LUOGU]P1443 马的遍历
    NOIP 2017 D2T1 奶酪
    [0] Hello World
    网络测速 风行天下
    zabbix自动发现与监控内存和CPU使用率最高的进程,监测路由器 风行天下
    网络性能测试工具iperf 风行天下
    Centos7下杀毒软件clamav的安装和使用 风行天下
    LINUX漏洞安全防护防火墙相关 风行天下
    smokeping配置方法 风行天下
    vb+MAPX 数据绑定
  • 原文地址:https://www.cnblogs.com/naix-x/p/3926564.html
Copyright © 2020-2023  润新知