卧薪尝胆,厚积薄发。
工艺
Date: Wed Aug 15 21:47:22 CST 2018 In Category: NoCategory

Description:

最小循环串。
$1\le n \le 300000$

Solution:

把串复制两倍建后缀自动机,每次沿最小的转移走 $n$ 步即可,转移数很大所以用 $map$ 。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
using namespace std;
int n;
#define MAXN 300010
int a[MAXN << 1];
int root,last,ptr;
struct node
{
int par,maxl;
map<int,int> tr;
node(int maxl_ = 0){par = 0;maxl = maxl_;}
}s[MAXN << 2];
int newnode(int k){++ptr;s[ptr].maxl = k;return ptr;}
void extend(int k)
{
int p = last;
int np = newnode(s[p].maxl + 1);
for(;p && s[p].tr[k] == 0;p = s[p].par)s[p].tr[k] = np;
if(p == 0)s[np].par = root;
else
{
int q = s[p].tr[k];
if(s[p].maxl + 1 == s[q].maxl)s[np].par = q;
else
{
int nq = newnode(s[p].maxl + 1);
s[nq].tr = s[q].tr;
s[nq].par = s[q].par;
s[q].par = nq;
s[np].par = nq;
for(;p && s[p].tr[k] == q;p = s[p].par)s[p].tr[k] = nq;
}
}
last = np;
return;
}
int main()
{
scanf("%d",&n);root = last = ptr = 1;
for(int i = 1;i <= n;++i)scanf("%d",&a[i]);
for(int i = n + 1;i <= 2 * n;++i)a[i] = a[i - n];
for(int i = 1;i <= 2 * n;++i)extend(a[i]);
int cur = root;
for(int i = 1;i <= n;++i)
{
cout << (s[cur].tr.begin() -> first) << " ";
cur = (s[cur].tr.begin() -> second);
}
cout << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡