學習筆記 字尾排序

2022-04-29 23:18:11 字數 4288 閱讀 2669

字尾排序學多了以後就只會字首排序了(輸出1-n的整數)

存個板子 倍增

\(code\ below:\)

#include #define ll long long

using namespace std;

const int maxn=1000000+10;

int n,m,sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn];

char a[maxn];

void sa()

for(i=1;i<=n;i++) rnk[sa[i]]=i;

for(i=1;i<=n;i++)

}signed main()

題意:問本質不同的子串數量

其實就是減去相鄰字尾的 \(lcp\),即 \(height\) 陣列

\(code\ below:\)

#include using namespace std;

const int maxn=1000+10;

int n,m,sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn],ans;

char a[maxn];

void sa()

for(int i=1;i<=n;i++) rnk[sa[i]]=i;

for(int i=1;i<=n;i++)

}int main()

return 0;

}

\(sp705\) 就是資料範圍開大一點,\(ans\) 開個 \(long\ long\)

題意:求最長重複 \(2\) 次不重疊子串

正解 \(o(n^2)\),但是我們可以用字尾陣列+二分優化到 \(o(n\log n)\)

處理出 \(height\) 陣列後二分長度,如果 \(height就重置,否則處理出連續一段區間的 \(minsa\) 和 \(maxsa\),若 \(maxsa-minsa>k\) 就說明有兩個子串

\(code\ below:\)

#include using namespace std;

const int maxn=50000+10;

int n,m,a[maxn],sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn],ans;

void sa()

for(int i=1;i<=n;i++) rnk[sa[i]]=i;

for(int i=1;i<=n;i++)

}int check(int k)

} return 0;

}int main()

for(int i=1;i<=n;i++) scanf("%d",&a[i]);

for(int i=1;i>1;

if(check(mid)) l=mid;

else r=mid-1;

} l++;

printf("%d\n",(l>=5)?l:0);

return 0;

}

題意:求重複次數最多的連續重疊子串

在 \(height\) 陣列上瞎搞

\(code\ below:\)

#include #include #include #include using namespace std;

const int maxn=100000+10;

int n,m,rmq[maxn][18],sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn];

char a[maxn];

void sa()

for(int i=1;i<=n;i++) rnk[sa[i]]=i;

for(int i=1;i<=n;i++)

for(int i=1;i<=n;i++) rmq[i][0]=i;

for(int j=1;j<18;j++)

for(int i=1;i+(1return h[query(l+1,r)];

}int main()

sa();

int k,t,now=0,ans=0;

for(int i=1;i=0&&lcp(t,t+i)>=i-k%i) now++;

ans=max(ans,now);

}} printf("%d\n",ans+1);

} return 0;

}

題意:求 \(\frac-2\times \sum_

for(i=1;i<=n;i++) rnk[sa[i]]=i;

for(i=1;i<=n;i++)

}signed main()

top=0;

for(int i=n;i>=2;i--)

for(int i=2;i<=n;i++) ans-=2ll*l[i]*r[i]*h[i];

printf("%lld\n",ans);

return 0;

}題意:求每乙個 \(i\),字串 \(1-i\) 中本質不同串的個數

因為字符集很大,考慮用字尾陣列

我們們後面新增乙個字元換成刪除乙個字元,那麼就是在雙向鍊錶上刪除兩個 \(height\) 的 \(max\),保留兩個 \(height\) 的 \(min\),反著來一下

\(code\ below:\)

#include #define ll long long

using namespace std;

const int maxn=100000+10;

int n,m,a[maxn],mp[maxn],sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn],pre[maxn],nxt[maxn];ll ans[maxn];

void sa()

for(i=1;i<=n;i++) rnk[sa[i]]=i;

for(i=1;i<=n;i++)

}int main()

sort(mp+1,mp+n+1);

int cnt=unique(mp+1,mp+n+1)-mp-1;

for(int i=1;i<=n;i++)

a[i]=lower_bound(mp+1,mp+cnt+1,a[i])-mp;

reverse(a+1,a+n+1);

sa();

for(int i=1;i<=n;i++) pre[i]=i-1,nxt[i]=i+1;

for(int i=1;i<=n;i++)

for(int i=n;i>=1;i--) ans[i]+=ans[i+1];

for(int i=n;i>=1;i--) printf("%lld\n",ans[i]);

return 0;

}

字尾陣列好題!

因為 \(r\) 相似是 \(r-1\) 相似但 \(r-1\) 相似不是 \(r\) 相似,我們考慮現將 \(height\) 從大到小排序,然後用並查集維護一下。因為 \(a_p\times a_q\) 取最大時 \(a_p\) 和 \(a_q\) 可能為負數,那麼我們記錄乙個最大值和最小值,每次相乘一下,更新答案。最終要求的方案數是 \(num\) 的字尾和,\(a_p\times a_q\) 最大時為 \(ans\) 的字尾最大值

\(code\ below:\)

#include #define int long long

#define ll long long

using namespace std;

const int maxn=600000+10;

int n,m,b[maxn],val[maxn],sa[maxn],tax[maxn],rnk[maxn],tp[maxn],h[maxn],fa[maxn],siz[maxn],max[maxn],min[maxn];ll num[maxn],ans[maxn];

char a[maxn];

void sa()

for(i=1;i<=n;i++) rnk[sa[i]]=i;

for(i=1;i<=n;i++)

}int find(int x)

void merge(int x,int y)

bool cmp(int x,int y)

signed main()

for(int i=0;i=0;i--) num[i]+=num[i+1],ans[i]=max(ans[i],ans[i+1]);

for(int i=0;ireturn 0;

}

字尾陣列學習筆記

要用好字尾陣列要先理解裡面幾個陣列的概念 sa i 表示字典序第i大的字尾下標 字典序排名依次是1 len stri ng ra nk i 表示下標為i的字尾字典序排名 he ight i 表示sa i 和sa i 1 最長公共字首的長度.乙個性質 lc p su ffix i suff ix j ...

字尾陣列 學習筆記

字尾陣列是處理字串的強有力的工具 在字串處理當中,字尾樹和字尾陣列都是非常有力的工具。其實字尾陣列是字尾樹的乙個非常精巧的替代品,它比字尾樹容易程式設計實現,能夠實現字尾樹的很多功能而時間複雜度也不太遜色,並且,它比字尾樹所占用的空間小很多。可以說,在資訊學競賽中字尾陣列比字尾樹要更為實用。我們定義...

字尾陣列 學習筆記

剛剛學完回文自動機 來學字尾陣列 一開始思路看得懂 但是 看不懂呀 一堆神仙 洛谷p3809 勿謂我,何強過者,炸哉!我們需要一種新的演算法 字尾陣列 首先,輸入字串 scanf s ch 1 n strlen ch 1 然後,按照題意 suffix sort ch for int i 1 i n ...