描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为一段数构成的数列。
现在小Hi想知道一部作品中所有长度为K的旋律中出现次数最多的旋律的出现次数。但是K不是固定的,小Hi想知道对于所有的K的答案。
parants树上拓扑
合并endpos
1 #pragma GCC optimize(2) 2 #pragma G++ optimize(2) 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 #include<iostream> 7 #include<cstdio> 8 #include<queue> 9 10 #define N 2000007 11 using namespace std; 12 inline int read() 13 { 14 int x=0,f=1;char ch=getchar(); 15 while(!isdigit(ch)){if(ch==‘-‘)f=-1;ch=getchar();} 16 while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();} 17 return x*f; 18 } 19 20 int n; 21 char s[N]; 22 struct sam 23 { 24 int last,cnt,rt; 25 int c[N][26],fa[N],mx[N],endpos[N]; 26 sam(){last=cnt=rt=1;} 27 void extend(int x) 28 { 29 int p=last,np=last=++cnt;mx[np]=mx[p]+1,endpos[np]=1; 30 while(p&&!c[p][x]) 31 { 32 c[p][x]=np; 33 p=fa[p]; 34 } 35 if(!p)fa[np]=rt; 36 else 37 { 38 int q=c[p][x]; 39 if(mx[q]==mx[p]+1)fa[np]=q; 40 else 41 { 42 int nq=++cnt;mx[nq]=mx[p]+1; 43 memcpy(c[nq],c[q],sizeof(c[q])); 44 fa[nq]=fa[q]; 45 fa[q]=fa[np]=nq; 46 while(c[p][x]==q)c[p][x]=nq,p=fa[p]; 47 } 48 } 49 } 50 int du[N],now=1,pre=0;queue<int>q[2]; 51 void init_endpos() 52 { 53 memset(du,0,sizeof(du)); 54 for (int i=cnt;i>1;i--) 55 du[fa[i]]++; 56 for (int i=1;i<=cnt;i++) 57 if(!du[i])q[pre].push(i),du[i]=-1; 58 while(!q[pre].empty()) 59 { 60 while(!q[pre].empty()) 61 { 62 int x=q[pre].front();q[pre].pop(); 63 endpos[fa[x]]+=endpos[x]; 64 du[fa[x]]--; 65 if(!du[fa[x]])q[now].push(fa[x]); 66 } 67 swap(pre,now); 68 } 69 } 70 int ans[N]; 71 void solve() 72 { 73 memset(ans,0,sizeof(ans)); 74 for (int i=1;i<=cnt;i++) 75 ans[mx[i]]=max(ans[mx[i]],endpos[i]); 76 for (int i=n-1;i>=1;i--) 77 ans[i]=max(ans[i],ans[i+1]); 78 for (int i=1;i<=n;i++) 79 printf("%d\n",ans[i]); 80 } 81 }sam; 82 83 int main() 84 { 85 scanf("%s",s+1),n=strlen(s+1); 86 for (int i=1;i<=n;i++) 87 sam.extend(s[i]-‘a‘); 88 sam.init_endpos(); 89 sam.solve(); 90 }