golang兩個協程交替列印1-100的奇數偶數
阿新 • • 發佈:2020-10-11
簡介
字尾陣列用於解決字串問題。至於到底解決什麼,並不是很清楚。
字尾排序
對於一個字串\(S\),我們可以\(O(n\log n)\)對它的所有後綴排序。
具體方法是倍增。我們先對\(S_{i,i+2^{k-1}-1}\)排序,然後再來解決\(S_{i,i+2^k-1}\)。這相當於我們對一些二元組\((rank_i,rank_{i+2^{k-1}})\)排序,最後得出答案。
對於某一維已經排好序的二元組,基數排序可以\(O(n)\)完美解決。
應用
光有這個玩意兒其實並沒有什麼用。我們真正需要的其實是由它衍生出來的\(height\)陣列求\(lcp\)。
定義\(lcp(i,j)\)為排名
下面給出一個重要性質:
\(lcp(i,j)=\min(lcp(i,k),lcp(k,j)),i\le k\le j\)
證明略。
那麼,我們設\(height_i=lcp(i,i-1)\),是不是就有\(lcp(i,j)=\min\{height_k\},i<k\le j\)?於是如果我們把\(height\)求出來,就可以用ST表算出任意2個字尾的\(lcp\)了。
現在假設\(h_i=height_{rk_i}\),那麼\(h_i\)就代表\(lcp(rk_i,rk_i-1)\)了。它有一個性質:
\(h_i\ge h_{i-1}-1\)
很抱歉,並沒有證明。
有了這個,就可以\(O(n)\)計算\(height_i\)了。
程式碼:
#include<bits/stdc++.h> using namespace std; const int N=1e6; int n,m=127,sa[N+10],rk[N+10],tp[N+10],tx[N+10]; //sa[i]:排名為i的字尾的位置 //rk[i]:位置為i的字尾的排名 (可以得出rk[sa[i]]=sa[rk[i]]=i) //tp[i]:排名為i的第二關鍵字的第一關鍵字的位置 (可以得出rk[tp[i]]就是第一關鍵字) //tx[i]:一個桶,沒什麼好說的 char s[N+10]; inline int Read() { int x=0,f=1;char ch=getchar(); while(!isdigit(ch)&&ch!='-') ch=getchar(); ch=='-'?f=-1:x=ch-'0'; while(isdigit(ch=getchar())) x=x*10+ch-'0'; return x*f; } inline void radix_sort() { for(register int i=1;i<=m;++i) tx[i]=0; for(register int i=1;i<=n;++i) tx[rk[i]]++; for(register int i=2;i<=m;++i) tx[i]+=tx[i-1];//tx[i]字首和就可以第一關鍵字最多排到第幾名 for(register int i=n;i>=1;--i) sa[tx[rk[tp[i]]]--]=tp[i];//倒序著做,這樣當第一關鍵字相同時,第二關鍵字大的會排在後面位置 } inline void sufsort() { for(register int i=1;i<=n;++i) rk[i]=s[i],tp[i]=i; radix_sort(); for(register int k=1;k<=n;k<<=1) { int len=0; for(register int i=n-k+1;i<=n;++i) tp[++len]=i; for(register int i=1;i<=n;++i) if(sa[i]>k) tp[++len]=sa[i]-k; radix_sort(); swap(rk,tp); rk[sa[1]]=len=1; for(register int i=2;i<=n;++i) { if(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k]) rk[sa[i]]=len; else rk[sa[i]]=++len; } m=len; if(len==n) break; } } inline void gethe() { int k=0; for(register int i=1;i<=n;++i) rk[sa[i]]=i; for(register int i=1;i<=n;++i) { if(rk[i]==1) continue; if(k) --k; int j=sa[rk[i]-1]; while(j+k<=n&&i+k<=n&&s[i+k]==s[j+k]) ++k; he[rk[i]]=k; } } int main() { scanf("%s",s+1); n=strlen(s+1); sufsort(); for(register int i=1;i<=n;++i) cout<<sa[i]<<" "; return 0; }