• <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
            日歷
            <2025年5月>
            27282930123
            45678910
            11121314151617
            18192021222324
            25262728293031
            1234567
            統計
            • 隨筆 - 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 閱讀(1548) 評論(0)  編輯 收藏 引用
             
            Copyright © TimTopCoder Powered by: 博客園 模板提供:滬江博客
            久久影视综合亚洲| 天天久久狠狠色综合| 久久精品人人做人人爽电影| 综合久久给合久久狠狠狠97色| 久久精品免费一区二区| 99久久免费国产精精品| 香蕉99久久国产综合精品宅男自| 午夜天堂精品久久久久| 久久国产精品国语对白| 久久久噜噜噜www成人网| 久久精品无码av| 国产精品一区二区久久不卡| 三级片免费观看久久| 久久伊人精品青青草原高清| 久久强奷乱码老熟女网站| 色综合久久88色综合天天| 国产成人精品久久| 亚洲国产综合久久天堂| 亚洲综合婷婷久久| 日韩久久久久久中文人妻| 国产精品久久久久免费a∨| 国产99久久久国产精品~~牛| 色8久久人人97超碰香蕉987| 亚洲精品WWW久久久久久| 精品久久久久久久久久中文字幕| 久久久亚洲欧洲日产国码aⅴ| 久久久久久久久66精品片| 久久99精品久久久久久齐齐| 青青青青久久精品国产h| AV无码久久久久不卡蜜桃| .精品久久久麻豆国产精品| 久久久精品国产sm调教网站| 亚洲国产精品无码久久久秋霞2| 久久综合视频网| 狠狠色丁香婷婷久久综合| 久久影视综合亚洲| 久久久久久亚洲精品影院| 久久精品视频一| 少妇人妻88久久中文字幕| 久久精品人人槡人妻人人玩AV| 久久婷婷激情综合色综合俺也去|