后缀数组 --- HDU 3518 Boring counting
?Boring counting
Problem's Link: ??http://acm.hdu.edu.cn/showproblem.php?pid=3518
?
Mean:?
給你一個(gè)字符串,求:至少出現(xiàn)了兩次(無重疊)的子串的種類數(shù)。
analyse:
后綴數(shù)組中height數(shù)組的運(yùn)用,一般這個(gè)數(shù)組用得很少。
總體思路:分組統(tǒng)計(jì)的思想:將相同前綴的后綴分在一個(gè)組,然后對(duì)于1到len/2的每一個(gè)固定長(zhǎng)度進(jìn)行統(tǒng)計(jì)ans。
首先我們先求一遍后綴數(shù)組,并把height數(shù)組求出來。height數(shù)組代表的含義是:字典序相鄰(即rank數(shù)組相鄰)的兩個(gè)后綴的最長(zhǎng)公共前綴的長(zhǎng)度。
由于子串不能重疊,那么就可以確定出子串長(zhǎng)度的取值范圍:1~len/2。(維護(hù)sa[]的最大值和最小值是為了判斷排名相鄰兩個(gè)字符串的距離是否大于k,只有大于k才能保證不重疊)。
接下來我們對(duì)1~len/2的每一個(gè)固定長(zhǎng)度進(jìn)行統(tǒng)計(jì)該長(zhǎng)度的子串有多少種,一路累加即得答案。
關(guān)鍵是要理解使用height數(shù)組進(jìn)行分組統(tǒng)計(jì)的過程。
Time complexity: O(nlogn)
?
Source code:?
/* * this code is made by crazyacking * Verdict: Accepted * Submission Date: 2015-05-09-21.22 * Time: 0MS * Memory: 137KB */ #include <queue> #include <cstdio> #include <set> #include <string> #include <stack> #include <cmath> #include <climits> #include <map> #include <cstdlib> #include <iostream> #include <vector> #include <algorithm> #include <cstring> #define LL long long #define ULL unsigned long long using namespace std; const int MAXN=1010; //以下為倍增算法求后綴數(shù)組 int 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(const char *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 sa[MAXN],Rank[MAXN],height[MAXN]; //求height數(shù)組 void calheight(const char *r,int *sa,int n){int i,j,k=0;for(i=1;i<=n;i++) Rank[sa[i]]=i;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; } char str[MAXN]; int solve(int k,int len) {int maxx=0,minn=INT_MAX,ans=0;for(int i=1;i<=len;++i){if(height[i]>=k)maxx=max(maxx,max(sa[i-1],sa[i])),minn=min(minn,min(sa[i-1],sa[i]));else{if(maxx-minn>=k) ans++;maxx=0,minn=INT_MAX;}}if(maxx-minn>=k)ans++;return ans; } int main() {while(~scanf("%s",str) && strcmp(str,"#")!=0){int len=strlen(str);/**< 傳入?yún)?shù):str,sa,len+1,ASCII_MAX+1 */da(str,sa,len+1,130);/**< str,sa,len */calheight(str,sa,len);LL ans=0;for(int i=1;i<=len/2;++i)ans+=solve(i,len);cout<<ans<<endl;}return 0; } View Code?
轉(zhuǎn)載于:https://www.cnblogs.com/crazyacking/p/4490844.html
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎(jiǎng)!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的后缀数组 --- HDU 3518 Boring counting的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YMP框架学习笔记(二)------基于
- 下一篇: Rsync 同步搭建