题意:
给一个长度为n的字符串s[0..n-1],但i的后继不再是i+1,而是(i*i+1)%n,求所有长度为n的“子串”中,字典序最大的是谁
n<=150000
分析:
如果是一般的字符串,那么直接求出后缀数组就行,但现在后继关系发生了变化
我们在倍增求后缀数组的过程中,只关心某个位置的下个2^k的后继,于是可以先倍增预处理出每个位置的nx[i][j]表示位置i的下个2^j的后继是谁
时间复杂度O(nlogn)
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=2e5; 4 char s[maxn+50]; 5 int sa[maxn+50],rk[maxn+50]; 6 int t[maxn+50],t2[maxn+50],c[maxn+50]; 7 int nx[maxn+5][19]; 8 int len,k; 9 queue<int> q[maxn+5]; 10 void getsa(int m)//m表示最大字符的编码 11 { 12 memset(t,-1,sizeof(t)); 13 memset(t2,-1,sizeof(t2)); 14 int *x=t,*y=t2; 15 for(int i=0;i<m;++i) c[i]=0; 16 for(int i=0;i<len;++i) c[x[i]=s[i]]++; 17 for(int i=1;i<m;++i) c[i]+=c[i-1]; 18 for(int i=len-1;i>=0;--i) sa[--c[x[i]]]=i; 19 for(int j=0,k=1;k<=len;k<<=1,++j) 20 { 21 /*int p=0; 22 for(int i=len-k;i<len;++i) y[p++]=i; 23 for(int i=0;i<len;++i) if(sa[i]>=k) y[p++]=sa[i]-k;*/ 24 25 int p=0; 26 for(int i=0;i<len;++i) q[nx[i][j]].push(i); 27 for(int i=0;i<len;++i) 28 while(!q[sa[i]].empty()) 29 { 30 y[p++]=q[sa[i]].front(); 31 q[sa[i]].pop(); 32 } 33 34 for(int i=0;i<m;++i) c[i]=0; 35 for(int i=0;i<len;++i) c[x[y[i]]]++; 36 for(int i=0;i<m;++i) c[i]+=c[i-1]; 37 for(int i=len-1;i>=0;--i) sa[--c[x[y[i]]]]=y[i]; 38 swap(x,y); 39 p=1,x[sa[0]]=0; 40 for(int i=1;i<len;++i) 41 if(y[sa[i-1]]==y[sa[i]]&&y[nx[sa[i-1]][j]]==y[nx[sa[i]][j]]) x[sa[i]]=p-1;else x[sa[i]]=p++; 42 if(p>=len) break; 43 m=p; 44 } 45 } 46 int main() 47 { 48 int T; 49 scanf("%d",&T); 50 for(int cas=1;cas<=T;++cas) 51 { 52 printf("Case #%d: ",cas); 53 scanf("%d",&len); 54 scanf("%s",s); 55 for(int i=0;i<len;++i) nx[i][0]=(1LL*i*i+1)%len; 56 for(int j=1;j<=18;++j) 57 for(int i=0;i<len;++i) nx[i][j]=nx[nx[i][j-1]][j-1]; 58 getsa('9'+1); 59 int pos=sa[len-1]; 60 for(int i=1;i<=len;++i,pos=nx[pos][0]) printf("%c",s[pos]); 61 printf("\n"); 62 } 63 64 // for(int i=0;i<n;++i) printf("%d ",sa[i]);printf("\n"); 65 // for(int i=0;i<n;++i) printf("%d ",rk[i]);printf("\n"); 66 // for(int i=0;i<n;++i) printf("%d ",height[i]);printf("\n"); 67 return 0; 68 69 }