• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            Tim's Programming Space  
            Tim's Programming Space
            日歷
            <2009年11月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345
            統計
            • 隨筆 - 20
            • 文章 - 1
            • 評論 - 40
            • 引用 - 0

            導航

            常用鏈接

            留言簿(3)

            隨筆檔案

            文章檔案

            搜索

            •  

            最新評論

            閱讀排行榜

            評論排行榜

             
            前兩天在yjw神牛和hyf神牛的共同努力下終于學會了后綴數組O(nlogn)倍增構造方法。

            構造:
            定義s[k][i]表示從s字符串的第i位開始的長度為k的一個字符串(后綴),不夠的補零,sa[k][i]表示在所有長度為k的后綴中排序后大小為第i的后綴的位置。顯然sa[1]可以直接qsort得到。當sa[k]求到過后,sa[2k]的每個元素都可以O(1)比較得出,這時用桶排,把sa[k]中排名相同的放在一起(放在一個桶里),那么對于每個不同的桶中的元素,他們之間的大小關系就已經確定了,對于同一個桶中的元素,s[2k][i]的前k位是一樣的,可能不一樣只有后k位,而這個我們是已經得到了的,所以通過sa[k][i]可以算出sa[2k][i-k],桶排把排序過程復雜度降成了O(n),總體構造的復雜度就成了O(nlogn)。DC3算法貌似可以把復雜度降到O(n)...暫時只有膜拜的份了。

            現在定義sa[i]為所有后綴排好序后的第i個后綴在原序列中的位置。
            定義rank[i]為后綴s[i]在后綴排好序的序列中的排名。
            當sa數組求出來了過后,就可以構造h和height數組了。
            定義height數組為排好序的后綴中相鄰兩項的LCP(最常公共前綴),即height[i] = LCP(sa[i],sa[i-1])。
            定義h數組為原序列中的某個后綴與排好序的后綴中它的前一個的LCP,即h[i] = LCP(i,sa[rank[i]-1])。

            然后有一個hyf和yjw神牛都不知道怎么來的很牛X的定理:h[i]>=h[i-1]-1。。。所以就可以在O(n)時間內直接for出這個h數組來。。。(這步是最詭異也最精髓的,因為沒有這個數組后綴數組就沒什么用了。。求神牛們講解下這個定理的證明。。)
            求出了h數組后height數組也可以直接得到。

            實現方式是用了兩個指針輪番上陣,看起來可能會有點糾結。。

            應用:
            有了h和height數組后,我們就可以用它來做很多事情。但我還不是很熟,只會求一個字符串里面可以相交的最長重復字串的長度。。
            cii(uva?)3901 Editor就是這樣一道題。
            比如abcabcabc的最長重復字串就是abcabc。
            其實求出了h和height數組后就變得很簡單,就是h或height數組中最大的一個。

            歡迎大牛神牛們前來補充和指正!

             1 /*
             2  * $Date: Fri Nov 27 09:00:37 2009 CST
             3  * $File: 3901.cpp
             4  */
             5 #include <iostream>
             6 #include <cstdio>
             7 #include <cstdlib>
             8 #include <cstring>
             9 #include <algorithm>
            10 #define MAXLEN 50000
            11 
            12 using namespace std;
            13 
            14 char s[MAXLEN+1];
            15 bool cmp(const int &a,const int &b){
            16     return s[a]<s[b];
            17 }
            18 
            19 int sa[MAXLEN+1],rank[MAXLEN+1],tmp1[MAXLEN+1],tmp2[MAXLEN+1];
            20 int h[MAXLEN+1],height[MAXLEN+1];
            21 
            22 void Solve(){
            23     scanf("%s",s);
            24     int n = strlen(s);
            25     s[n++= 0;
            26     for (int i = 0; i<n; i++)
            27         sa[i] = i;
            28     sort(sa,sa+n,cmp);
            29     
            30     rank[sa[0]] = 0;
            31     for (int i = 1; i<n; i++)
            32         if (s[sa[i]]==s[sa[i-1]])
            33             rank[sa[i]] = rank[sa[i-1]];
            34         else
            35             rank[sa[i]] = rank[sa[i-1]]+1;
            36 
            37     int *s1 = sa,*s2 = tmp1,*= tmp2, *= rank;
            38     for (int i = 1; i<n&&r[sa[n-1]]<n-1; i<<=1){
            39         //b is the barrel
            40         for (int j = 0; j<n; j++)
            41             b[r[s1[j]]] = j;
            42         for (int j = n-1; j>=0; j--)
            43             if (s1[j]>=i)
            44                 s2[b[r[s1[j]-i]]--= s1[j]-i;
            45         for (int j = n-i; j<n; j++)
            46             s2[b[r[j]]] = j;
            47         swap(s1,s2);
            48         b[s1[0]] = 0;//cause the barrel is now useless, use b as the new rank array
            49         for (int j = 1; j<n; j++)
            50             if (r[s1[j]]!=r[s1[j-1]]||r[s1[j]+i]!=r[s1[j-1]+i])
            51                 b[s1[j]] = b[s1[j-1]]+1;
            52             else
            53                 b[s1[j]] = b[s1[j-1]];
            54         swap(b,r);
            55     }
            56     //calc 
            57     for (int i = 0; i<n; i++){
            58         if (r[i] == 0)
            59             h[i] = 0;
            60         else if (i == 0||h[i-1== 0)
            61             for (h[i] = 0; s[i+h[i]]==s[s1[r[i]-1]+h[i]];h[i]++);
            62         else 
            63             for (h[i]=h[i-1]-1 ; s[i+h[i]]==s[s1[r[i]-1]+h[i]];h[i]++);
            64     }
            65     int Ans = 1;
            66     for (int i = 0; i<n; i++)
            67         Ans = max(Ans,h[i]);
            68     printf("%d\n",Ans);
            69 }
            70 int main(){
            71     int t;
            72     scanf("%d",&t);
            73     while (t--)
            74         Solve();
            75     return 0;
            76 }
            77 

            posted on 2009-11-27 09:06 TimTopCoder 閱讀(1550) 評論(0)  編輯 收藏 引用
             
            Copyright © TimTopCoder Powered by: 博客園 模板提供:滬江博客
            国产精品久久久久影院色| 久久99精品久久久久婷婷| 国产成人AV综合久久| 久久亚洲国产精品成人AV秋霞 | 国产激情久久久久影院小草 | 久久亚洲高清综合| 久久久久亚洲AV无码专区体验| 国产99久久久国产精品~~牛| 久久久久九国产精品| 日本精品久久久久中文字幕8| 亚洲国产精品无码久久SM| 性做久久久久久久久久久| 欧美综合天天夜夜久久| 久久久久久国产精品无码下载| 狠狠色综合网站久久久久久久高清| 色婷婷久久久SWAG精品| 久久青青草原精品国产| 久久久久久毛片免费看| 99久久99这里只有免费的精品| 污污内射久久一区二区欧美日韩| 国产精品免费福利久久| 精品国产日韩久久亚洲| 久久五月精品中文字幕| 国产精品久久久久久一区二区三区| 一级做a爰片久久毛片免费陪| 亚洲精品tv久久久久| 久久综合狠狠综合久久激情 | 欧美久久久久久| 伊人久久大香线蕉综合5g| 91麻精品国产91久久久久| 久久精品无码午夜福利理论片| 少妇久久久久久被弄到高潮 | 久久久久久A亚洲欧洲AV冫 | 亚洲精品乱码久久久久久按摩| 精品久久久久久久久中文字幕| 久久这里只有精品首页| 精品久久久久久久中文字幕 | 99久久这里只精品国产免费| 久久WWW免费人成—看片| 国产精品久久久久一区二区三区| 久久综合狠狠色综合伊人|