bzoj2882工艺(最小表示法)

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]);
}
View Code

 

posted @ 2019-05-11 12:57  hfctf0210  阅读(202)  评论(0编辑  收藏  举报