题意:给定一个长度为n(n<=150000)的字符串,每个下标i与(i*i+1)%n连边,求从任意下标出发走n步能走出的字典序最大的字符串。
把下标看成结点,由于每个结点有唯一的后继,因此形成的是内向基环树森林,相当于求基环树上字典序最大的路径。
实际上基环树和树一样是可以通过倍增得到走2^k步能走到的结点的,然后后缀数组又可以通过倍增求出长度为2^k的后缀的字典序,两者结合一下就可以对所有路径按字典序排序了。
复杂度$O(nlogn)$,感觉这应该是标解吧,不过由于数据可能比较随机因此直接BFS也能过。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=150000+10,mod=998244353; 5 int c[N],sa[N],buf1[N],buf2[N],buf3[N],n,ka,nxt[N][20]; 6 char buf[N]; 7 int s[N]; 8 void Sort(int* x,int* y,int m) { 9 for(int i=0; i<m; ++i)c[i]=0; 10 for(int i=0; i<n; ++i)++c[x[i]]; 11 for(int i=1; i<m; ++i)c[i]+=c[i-1]; 12 for(int i=n-1; i>=0; --i)sa[--c[x[y[i]]]]=y[i]; 13 } 14 void da(int* s,int n,int m=1000) { 15 int *x=buf1,*y=buf2,*z=buf3; 16 x[n]=y[n]=-1; 17 for(int i=0; i<n; ++i)x[i]=s[i],y[i]=i; 18 Sort(x,y,m); 19 for(int k=1,j=0; k<n; k<<=1,++j) { 20 int p=0; 21 for(int i=0; i<n; ++i)z[i]=x[nxt[i][j]],y[i]=i; 22 Sort(z,y,m); 23 for(int i=0; i<n; ++i)y[i]=sa[i]; 24 Sort(x,y,m),p=1,y[sa[0]]=0; 25 for(int i=1; i<n; ++i)y[sa[i]]=x[sa[i-1]]==x[sa[i]]&&x[nxt[sa[i-1]][j]]==x[nxt[sa[i]][j]]?p-1:p++; 26 if(p==n)break; 27 swap(x,y),m=p; 28 } 29 } 30 int main() { 31 int T; 32 for(scanf("%d",&T); T--;) { 33 printf("Case #%d: ",++ka); 34 scanf("%d%s",&n,buf); 35 for(int i=0; i<n; ++i)s[i]=buf[i]; 36 for(int i=0; i<n; ++i)nxt[i][0]=((ll)i*i+1)%n; 37 for(int k=1; k<20; ++k) 38 for(int i=0; i<n; ++i) 39 nxt[i][k]=nxt[nxt[i][k-1]][k-1]; 40 da(s,n); 41 for(int i=0,u=sa[n-1]; i<n; ++i,u=nxt[u][0])printf("%c",s[u]); 42 puts(""); 43 } 44 return 0; 45 }