POJ 1743 Musical Theme(尾碼數組 求最長不重複子串)

來源:互聯網
上載者:User

對於尾碼數組強烈建議看國家集訓隊 04年和09年的兩篇關於尾碼數組的論文

尾碼數組非常強大,但是這麼強大的資料結構理解起來不是那麼容易的,裡面涉及到好多知識點,要想徹底理解尾碼數組,表示需要一點功底才行

對於尾碼數組具體請看國家集訓對09年和04年的兩篇大牛關於尾碼數組的論文,兩篇結合起來看效果會更好,可能看第一第二遍的時候不是怎麼理解

這個是肯定的,相信那兩個大牛寫這兩篇論文的時候花的時間也不止幾天吧,人家花幾天寫的論文給你一下子就看懂了,你當人家寫的是小說啊,一般

像這種複雜的資料結構要多看幾遍,甚至當你認為你已經看懂之後不妨再多看幾遍,這樣會有更深的理解!

尾碼數組主要是兩個 一個是尾碼數組,一個是名次數組,這兩個數組相互搭配完成尾碼數組的強大功能

尾碼數組sa儲存的是拍名,也就是下標表示排名,內容表示排這個名的是第幾個尾碼

rank數組正好相反,是第下標個尾碼的排名

然後用倍增演算法實現對尾碼數組的構造,我開始看的時候沒看懂,後來稍微懂了之後發現這個演算法用的也不是什麼高深的演算法

對於這個演算法的理解還是要在對字串比較的過程有一定的理解,這個題目關鍵就是按照字元出現的位置對字元賦予了類似整數

比較的一個權值,在前面的字元大小最總要,也就是個十百千位那樣,先求一個長度的排名,然後根據一個的求兩個的,一次往後

最後完成整個尾碼數組的構造

構造完成之後這個尾碼數組好像還不能幹什麼事情,接下來又引進了height數組(具體定義請看論文),這個height數組儲存的是

排名相鄰的兩個尾碼的最長首碼,現在我們關鍵任務是怎樣在最短時間內構造出這個height數組,論文上給了O(n)的複雜度,

這個求法類似於動態規劃的思想,利用前面的結果,在其基礎之上跟新現在的結果

完了之後就是這個題目的內容了

這個題目的思想是二分枚舉,和判斷重複,然後按照height的值進行分組,分組完成之後判斷組內最大位置和最小位置的差值是否

滿足題目條件,判斷是否滿足題目要求,具體為什麼分組和最大位置最小位置差就能確定,看看下面代碼注釋

#include <iostream>#include <stdio.h>#include <algorithm>#include <math.h>using namespace std;#define maxn 21000#define ws ws1int wa[maxn],wb[maxn],wv[maxn],ws[maxn];int cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}void da(int *r,int *sa,int n,int m){int i,j,p,*x=wa,*y=wb,*t;for(i=0;i<m;i++) ws[i]=0;for(i=0;i<n;i++) ws[x[i]=r[i]]++;for(i=1;i<m;i++) ws[i]+=ws[i-1];for(i=n-1;i>=0;i--) sa[--ws[x[i]]]=i;for(j=1,p=1;p<n;j*=2,m=p){for(p=0,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<n;i++) wv[i]=x[y[i]];for(i=0;i<m;i++) ws[i]=0;for(i=0;i<n;i++) ws[wv[i]]++;for(i=1;i<m;i++) ws[i]+=ws[i-1];for(i=n-1;i>=0;i--) sa[--ws[wv[i]]]=y[i];for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;}return;}int rank[maxn],height[maxn];void calheight(int *r,int *sa,int n){int i,j,k=0;for(i=1;i<=n;i++) rank[sa[i]]=i;//在計算height的時候順便就把rank計算出來了,反正也要用for(i=0;i<n;height[rank[i++]]=k)for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);return;}int rec[maxn],rec1[maxn],sa[maxn];int n;bool check(int m){    int mmax=0,mmin=n;   /*這裡說的就是論文上對height數組進行分組    *這個分組是按照順序來分組的,也就是把整個height數組按照比m大和沒有m大分成一段一段,如果在    *在某一段記憶體在答案就說明成立    *還是按照自己的理解解釋一下這裡為什麼按照這樣分組就可以,為什麼是這個分組區間的最左邊和最右邊的不相交就可以    *想一想如果一個區間的height值都比m大,那麼這麼多組尾碼的前m個一定是相同的,因為是前一組前m個等於後一組m個,    *而後一的前m個又等於後後一組的,這樣推出來,所以這樣分組是正確的    */    for(int i=1;i<=n;i++)    {        if(height[i]<m)        {            mmax=sa[i];            mmin=sa[i];        }        else        {            mmax=max(mmax,max(sa[i],sa[i-1]));            mmin=min(mmin,min(sa[i],sa[i-1]));            if(mmax-mmin>m) return true;        }    }    return false;}int main(){    int i,j,k;    int left,right;    int mid;    int answer;    while(scanf("%d",&n),n)    {     for(i=0;i<n;i++)     scanf("%d",&rec1[i]);     for(i=0;i<n-1;i++)     rec[i]=rec1[i+1]-rec1[i]+100;     n--;     rec[n]=0;     da(rec,sa,n+1,200);//這裡是n+1 因為看這個函數裡面是 < n 的     calheight(rec,sa,n);//注意這裡面是 n 了因為看函數裡面是 <=n 的,所以這裡要注意     right=-1;     for(i=0;i < n ;i++)     if(right < height[i])     right=height[i];     //for(i=0;i<=n;i++)    // printf("%d ",height[i]);    // printf("\n");     if(!check(4))     {         printf("0\n");         continue;     }     left=4;     answer=4;     while(left <= right)     {         mid=(left+right)>>1;         if(check(mid))         {             answer=mid;             left=mid+1;         }         else         {             right=mid-1;         }     }     printf("%d\n",answer+1);    }    return 0;}

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.