每个节点都有唯一后继。所以,可以用倍增求后缀数组。
节点的前趋个数可能不唯一,所以我们可以用vector<int> pre[N][20]
来记录每个节点的前趋。
code
2964/3000 ms
命真大!
#include <iostream>
#include <time.h>
#include <vector>
#include <cmath>
using namespace std;
const int N=150002;
int T, n, cas;
char s[N];
int sa[N], cc[N], t1[N], t2[N];
int nex[N][22];
vector<int> pre[N][22];
int LG[N];
void perlude() {
for(int i=1;i<N;i++)
LG[i] = (int)log2(i);
}
void rmqProcess() {
int B = LG[n];
for(int i=0;i<n;i++)
for(int j=0;j<=B;j++)
nex[i][j]=-1, pre[i][j].clear();
for(int i=0;i<n;i++) {
int j=(1LL*i*i+1)%n;
nex[i][0] = j;
pre[j][0].push_back(i);
}
for(int i=1;i<=B;i++)
for(int j=0;j<n;j++) {
nex[j][i]=nex[nex[j][i-1]][i-1];
pre[nex[nex[j][i-1]][i-1]][i].push_back(j);
}
}
bool cmp(int *y, int a,int b,int k){
int a1=y[a];
int b1=y[b];
int a2=y[nex[a][k]];
int b2=y[nex[b][k]];
return (a1==b1)&&(a2==b2);
}
void build_sa(int m) {
int *x=t1,*y=t2;
for(int i=0;i<m;i++) cc[i]=0;
for(int i=0;i<n;i++) ++ cc[x[i]=(s[i]-'0')];
for(int i=1;i<m;i++) cc[i]+=cc[i-1];
for(int i=n-1;i>=0;i--) sa[--cc[x[i]]]=i;
int counter = 0;
for(int k=1;k<=n;k<<=1,counter++)
{
int p=0;
for(int i=0;i<n;i++)
for(int j=0;j<pre[sa[i]][counter].size();j++)
y[p++] = pre[sa[i]][counter][j];
for(int i=0;i<m;i++) cc[i]=0;
for(int i=0;i<n;i++) ++cc[x[y[i]]];
for(int i=1;i<m;i++) cc[i]+=cc[i-1];
for(int i=n-1;i>=0;i--) sa[--cc[x[y[i]]]]=y[i];
std::swap(x,y);
m=1, x[sa[0]]=0;
for(int i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i],sa[i-1],counter) ? m-1 : m++;
if (m>=n) break;
}
}
void print(int x) {
printf("Case #%d: ", ++cas);
for(int i=0;i<n;i++) {
printf("%c", s[x]);
x=(1LL*x*x+1)%n;
}
printf("
");
}
int main() {
perlude();
scanf("%d", &T);
while(T --) {
scanf("%d%s", &n,s);
rmqProcess();
build_sa(10);
print(sa[n-1]);
}
}