1. 程式人生 > >【BZOJ3227】串【廣義後綴自動機】

【BZOJ3227】串【廣義後綴自動機】

har truct last scanf names const 維護 isp col

題意

給出n個字符串,問每個字符串中有多少子串是這所有的n個字符串中至少k個的子串。

分析

廣義後綴自動機模板題。對這n個串建廣義後綴自動機,對於每個狀態維護兩個值cou[u]和lcu[u]分別代表擁有這個狀態的子串的數量和上一次更新到這個狀態的子串的數量。然後設f[u]為狀態u到祖先的所有結點有多少子串出現在至少k個字符串中。然後再跑一邊每個子串就可以了。

技術分享圖片
 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5
6 using namespace std; 7 const int maxn=1e5+100; 8 typedef long long LL; 9 string S[maxn]; 10 char s[maxn]; 11 struct state{ 12 int link,len; 13 int next[26]; 14 }st[2*maxn]; 15 int n,k,last,cur,sz; 16 int c[2*maxn]; 17 int cou[2*maxn],lcu[2*maxn];//不同子串數量,上一次出現的子串 18 LL f[maxn];
19 20 void init(){ 21 sz=1; 22 cur=last=0; 23 st[0].link=-1; 24 st[0].len=0; 25 } 26 void build_sam(int c){ 27 cur=sz++; 28 st[cur].len=st[last].len+1; 29 int p; 30 for(p=last;p!=-1&&st[p].next[c]==0;p=st[p].link) 31 st[p].next[c]=cur; 32 if
(p==-1) 33 st[cur].link=0; 34 else{ 35 int q=st[p].next[c]; 36 if(st[p].len+1==st[q].len) 37 st[cur].link=q; 38 else{ 39 int clone=sz++; 40 st[clone].len=st[p].len+1; 41 st[clone].link=st[q].link; 42 for(int i=0;i<26;i++) 43 st[clone].next[i]=st[q].next[i]; 44 for(;p!=-1&&st[p].next[c]==q;p=st[p].link) 45 st[p].next[c]=clone; 46 st[cur].link=st[q].link=clone; 47 } 48 } 49 last=cur; 50 } 51 int cmp(int a,int b){ 52 return st[a].len<st[b].len; 53 } 54 55 int main(){ 56 scanf("%d%d",&n,&k); 57 init(); 58 for(int i=1;i<=n;i++){ 59 scanf("%s",s); 60 S[i]=(string)s; 61 int len=strlen(s); 62 for(int i=0;i<len;i++) 63 build_sam(s[i]-a); 64 last=0; 65 } 66 for(int i=1;i<=n;i++){ 67 int u=0; 68 for(int j=0;j<S[i].length();j++){ 69 int c=S[i][j]-a; 70 u=st[u].next[c]; 71 for(int p=u;p!=-1&&lcu[p]!=i;p=st[p].link) 72 lcu[p]=i,cou[p]++; 73 } 74 } 75 for(int i=0;i<sz;i++) 76 c[i]=i; 77 sort(c,c+sz,cmp); 78 for(int i=0;i<sz;i++){ 79 int u=c[i]; 80 if(st[u].link!=-1){ 81 f[u]+=f[st[u].link]; 82 if(cou[u]>=k){ 83 f[u]+=st[u].len-st[st[u].link].len; 84 } 85 } 86 } 87 for(int i=1;i<=n;i++){ 88 int u=0; 89 LL res=0; 90 for(int j=0;j<S[i].length();j++){ 91 int c=S[i][j]-a; 92 u=st[u].next[c]; 93 res+=f[u]; 94 } 95 printf("%lld\n",res); 96 } 97 98 return 0; 99 }
View Code

【BZOJ3227】串【廣義後綴自動機】