O(nlogn)的做法十分显然,有三种可以做到O(nlogn)的:1、最容易的想法:把串扩展成两倍,然后跑一遍SA求后缀数组。2、求后缀同样也可以用SAM去求解,用map存一下。3、最暴力的方法:直接二分+hash比较第一位不同的。
其实这题想要让我们用最小表示法求解,然而我不会就来学一下。很容易发现这样一个规律,如果存在s[i+k]>s[j+k],那么s[i...i+k]开头的都不会是最小表示法开头,因为s[i...i+k]=s[j...j+k],所以从s[i...i+k]开头的串都会经过这里。出现这种情况,直接i+=k即可。又简便又好写,不过这种方法很容易忘。
#include<bits/stdc++.h> using namespace std; const int N=6e5+7; int n,a[N]; int solve() { int i=1,j=2; while(i<=n&&j<=n) { int k=0; while(j+k<=2*n&&a[i+k]==a[j+k])k++; if(j+k>2*n)break; if(a[i+k]>a[j+k])i=max(j,i+k+1),j=i+1; else j+=k+1; } return min(i,j); } int main() { scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&a[i]),a[i+n]=a[i]; int pos=solve(); for(int i=pos;i<pos+n;i++)printf("%d ",a[i]); }