HDU

题意:给定一个长度为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 }
原文地址:https://www.cnblogs.com/asdfsag/p/11644558.html