后缀数组 --- HDU 3518 Boring counting
生活随笔
收集整理的這篇文章主要介紹了
后缀数组 --- HDU 3518 Boring counting
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?Boring counting
Problem's Link: ??http://acm.hdu.edu.cn/showproblem.php?pid=3518
?
Mean:?
給你一個字符串,求:至少出現了兩次(無重疊)的子串的種類數。
analyse:
后綴數組中height數組的運用,一般這個數組用得很少。
總體思路:分組統計的思想:將相同前綴的后綴分在一個組,然后對于1到len/2的每一個固定長度進行統計ans。
首先我們先求一遍后綴數組,并把height數組求出來。height數組代表的含義是:字典序相鄰(即rank數組相鄰)的兩個后綴的最長公共前綴的長度。
由于子串不能重疊,那么就可以確定出子串長度的取值范圍:1~len/2。(維護sa[]的最大值和最小值是為了判斷排名相鄰兩個字符串的距離是否大于k,只有大于k才能保證不重疊)。
接下來我們對1~len/2的每一個固定長度進行統計該長度的子串有多少種,一路累加即得答案。
關鍵是要理解使用height數組進行分組統計的過程。
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; //以下為倍增算法求后綴數組 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數組 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);/**< 傳入參數: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?
轉載于:https://www.cnblogs.com/crazyacking/p/4490844.html
新人創作打卡挑戰賽發博客就能抽獎!定制產品紅包拿不停!總結
以上是生活随笔為你收集整理的后缀数组 --- HDU 3518 Boring counting的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YMP框架学习笔记(二)------基于
- 下一篇: Rsync 同步搭建