1. 程式人生 > >HDU 6194 後綴數組

HDU 6194 後綴數組

~~ div mage eight sca name 只有一個 height 說明

技術分享

題意:求出現恰好 k次的子串(可以重疊)的個數;

分析:

剛開始想到了是後綴數組,但是有什麽性質,具體怎麽做的沒有想到。回到主題來:

連續 k 次,說明這 k 個後綴排序後在一起,每次枚舉 長度的為 k 的區間,用RMQ算出最長公共前綴長度,這裏就有 len 個子串是 符合滿足 k 次的,但是又有可能過短而不止出現了 k次,那麽有多少呢?

技術分享

那麽就是 a 不屬於,len - height[j+1],前面也一樣。也就是每次只算他獨有的子串,但是你可能問 len > k 的時候,可以從新組成一組子串!

沒關系,他會在下一個 k 的區間內出現~~~

到這裏,離成功就只差一步了, k = 1 的時候,什麽意思? 獨一無二的子串個數,這時區間內只有一個後綴,那麽就有 len - sa[i] 個後綴是至少有 1 次的,再次去掉 那些>1 次的子串(height[i] ,height[j+1])

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 2000000+5;

int wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int sa[maxn];
int r[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 ranks[maxn],height[maxn]; void calheight(int *r,int *sa,int n) { int i,j,k=0; for(i=1; i<=n; i++) ranks[sa[i]]=i; for(i=0; i<n; height[ranks[i++]]=k) for(k?k--:0,j=sa[ranks[i]-1]; r[i+k]==r[j+k]; k++); return; } char str[maxn]; int f[maxn][20]; void init(int len) { for(int i = 1; i <= len; i++) f[i][0] = height[i]; for(int s = 1; (1<<s)<=len; s++) { int tmp = (1<<s); for(int i = 1; i+tmp-1<=len; i++) { f[i][s] = min(f[i][s-1],f[i+tmp/2][s-1]); } } } int cal(int l,int r) { int len = log2(r-l+1); int ans = min(f[l][len],f[r-(1<<len)+1][len]); return ans; } int main() { int t; scanf("%d",&t); while(t--) { int k; scanf("%d%s",&k,str); int len = strlen(str); for(int i = 0; i < len; i++) r[i] = str[i] - a + 1; r[len] = 0; da(r,sa,len+1,130); calheight(r,sa,len); init(len); int ans = 0; for(int i = 1; i+k-1<=len; i++) { int j = i+k-1; int tmp = height[i]; if(j+1<=len) tmp = max(tmp,height[j+1]); int x; if(k!=1) { x = cal(i+1,j); } else x = len - sa[i]; ans +=max(0,x-tmp); } printf("%d\n",ans); } return 0; }

HDU 6194 後綴數組